Skip to content

Commit

Permalink
Update repeat task handling for users without accounts
Browse files Browse the repository at this point in the history
  • Loading branch information
trisDeveloper committed Aug 2, 2024
1 parent 1ed0e93 commit 8a6d571
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 78 deletions.
90 changes: 45 additions & 45 deletions backend/focusty/focusty/settings.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#settings.py
# settings.py
import os
from pathlib import Path

Expand All @@ -10,66 +10,66 @@
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-$ll28-c=vwvzhz1p8%o5-ct(0r0&$vf@=+)c5k2frf(ncpufa-'
SECRET_KEY = "django-insecure-$ll28-c=vwvzhz1p8%o5-ct(0r0&$vf@=+)c5k2frf(ncpufa-"

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ['trisdev.pythonanywhere.com', '127.0.0.1']
ALLOWED_HOSTS = ["trisdev.pythonanywhere.com", "127.0.0.1"]

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'corsheaders',
'focusty_app',
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"rest_framework",
"corsheaders",
"focusty_app",
]

CORS_ORIGIN_ALLOW_ALL = True

MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
"corsheaders.middleware.CorsMiddleware",
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]

ROOT_URLCONF = 'focusty.urls'
ROOT_URLCONF = "focusty.urls"

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]

WSGI_APPLICATION = 'focusty.wsgi.application'
WSGI_APPLICATION = "focusty.wsgi.application"

AUTH_USER_MODEL = 'focusty_app.User'
AUTH_USER_MODEL = "focusty_app.User"
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}

Expand All @@ -79,26 +79,26 @@

AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]


# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/

LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = "en-us"

TIME_ZONE = 'Africa/Algiers'
TIME_ZONE = "Africa/Algiers"

USE_I18N = True

Expand All @@ -110,15 +110,15 @@
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/

STATIC_URL = '/static/'
STATIC_URL = "/static/"

# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

# Base url to serve media files
MEDIA_URL = '/media/'
MEDIA_URL = "/media/"

# Path where media is stored
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
MEDIA_ROOT = os.path.join(BASE_DIR, "media/")
2 changes: 2 additions & 0 deletions backend/focusty/focusty_app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class Task(models.Model):
title = models.CharField(max_length=255)
date = models.DateField()
time = models.TimeField(null=True)
repeatId = models.CharField(max_length=255, blank=True, null=True)
repeatParameters = models.JSONField(null=True, blank=True)
done = models.BooleanField(default=False)
description = models.CharField(max_length=255, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
Expand Down
51 changes: 37 additions & 14 deletions frontend/src/components/task-card.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,31 @@
import axios from 'axios'
import taskRepeat from './task-repeat.vue'
import { useStore } from '@/stores'
const props = defineProps(['fetchData', 'task', 'saveTask'])
const props = defineProps([
'fetchData',
'task',
'handleSaveThisOrAll',
'closeThisOrAll',
'openThisOrAll',
'deleteThisOrAll'
])
const store = useStore()
const deleteTask = async (task) => {
const deleteTask = async (task, deleteThisOrAll) => {
try {
closeTaskCard()
props.closeThisOrAll()
if (localStorage.getItem('userId')) {
await axios.delete(`/api/users/${store.user.id}/tasks/${task.id}/`, { done: task.done })
} else {
const localTasks = JSON.parse(localStorage.getItem('tasks')) || []
const updatedTasks = localTasks.filter((t) => t.id !== task.id)
localStorage.setItem('tasks', JSON.stringify(updatedTasks))
if (task.repeatId && deleteThisOrAll == 'all') {
const updatedTasks = localTasks.filter((t) => t.repeatId !== task.repeatId)
localStorage.setItem('tasks', JSON.stringify(updatedTasks))
} else {
const updatedTasks = localTasks.filter((t) => t.id !== task.id)
localStorage.setItem('tasks', JSON.stringify(updatedTasks))
}
}
} catch (error) {
// Handle errors
Expand Down Expand Up @@ -101,7 +115,11 @@ props.fetchData()
title="Delete Task"
icon="fa-regular fa-trash-can"
class="trash"
@click="deleteTask(store.selectedTask)"
@click="
store.selectedTask.repeatId
? props.openThisOrAll('delete')
: deleteTask(store.selectedTask, 'this')
"
/>
<!-- done icon -->
<font-awesome-icon
Expand All @@ -116,6 +134,7 @@ props.fetchData()
title="Repeat Task"
icon="fa-solid fa-repeat"
class="repeat"
:style="store.selectedTask.repeatParameters ? { color: '#3eff78e0' } : ''"
@click="openRepeatCard()"
/>
</div>
Expand All @@ -125,7 +144,7 @@ props.fetchData()
class="task-title"
v-model="store.selectedTask.title"
@input="updateTaskTitle"
@keyup.enter="props.saveTask"
@keyup.enter="props.handleSaveThisOrAll"
placeholder="Title"
/>
<font-awesome-icon icon="fa-solid fa-pencil" />
Expand Down Expand Up @@ -163,10 +182,13 @@ props.fetchData()
class="task-desc"
v-model="store.selectedTask.description"
@input="updateTaskDescription"
@keyup.enter="props.saveTask"
@keyup.enter="props.handleSaveThisOrAll"
placeholder="Description"
/>

<div v-if="props.deleteThisOrAll" class="thisOrAll">
<div @click="deleteTask(store.selectedTask, 'this')">This Task</div>
<div @click="deleteTask(store.selectedTask, 'all')">All Tasks</div>
</div>
<taskRepeat v-if="store.isRepeatOpen"></taskRepeat>
</div>
</template>
Expand All @@ -177,7 +199,7 @@ props.fetchData()
padding: 5px;
flex-grow: 1;
.done {
color: #393949;
color: #303030;
text-decoration: line-through;
transition: all 0.3s;
}
Expand All @@ -194,7 +216,7 @@ props.fetchData()
border-radius: 10px;
padding: 20px;
background-color: #0b0c0d;
border: 1px solid #8269ac;
border: 1px solid #303030;
box-shadow: 0px 2px 10px 2px #03030e41;
z-index: 10;
.task-actions {
Expand All @@ -204,10 +226,11 @@ props.fetchData()
color: #ddd;
font-size: 18px;
.trash,
.checkbox {
.checkbox,
.repeat {
padding-left: 10px;
&:hover {
color: #c4a3ff;
color: #818181;
}
}
}
Expand Down Expand Up @@ -251,7 +274,7 @@ props.fetchData()
display: flex;
align-items: center;
.date-picker {
border: 1px solid #a984ff;
border: 1px solid #303030;
background: #131518 !important;
position: absolute;
button {
Expand All @@ -262,7 +285,7 @@ props.fetchData()
}
}
.vc-popover-content-wrapper .vc-popover-content button {
background: #06061b !important;
background: #2b2b2b !important;
color: #fff;
}
.date-btn {
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/components/task-repeat.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,12 @@ const save = () => {
occurrences: repeatEnd.value == 'after' ? occurrences.value : null,
endDate: repeatEnd.value == 'on' ? endDate.value : null
},
repeatId: store.selectedTask.id
repeatId: store.selectedTask.repeatId ?? store.selectedTask.id
})
} else {
store.setSelectedTask({
...store.selectedTask,
repeatParameters: null,
repeatId: null
repeatParameters: null
})
}
} catch (error) {
Expand Down
Loading

0 comments on commit 8a6d571

Please sign in to comment.