Loading habits...
Загрузка привычек...
@@ -202,6 +334,13 @@ h3 {
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
+.habit-view {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+}
+
.habit-info h4 {
margin: 0 0 10px 0;
}
@@ -227,4 +366,43 @@ h3 {
margin-bottom: 15px;
text-align: center;
}
+
+/* Actions */
+.habit-actions button {
+ padding: 5px 10px;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ margin-left: 10px;
+}
+.edit-btn { background-color: #d8dee9; color: #4c566a; }
+.delete-btn { background-color: #bf616a; color: #fff; }
+
+/* Edit Form */
+.habit-edit-form {
+ width: 100%;
+}
+.habit-edit-form input[type="text"] {
+ width: 100%;
+ padding: 8px;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ margin-bottom: 10px;
+}
+.edit-days {
+ margin-bottom: 10px;
+}
+.edit-actions {
+ display: flex;
+ gap: 10px;
+ justify-content: flex-end;
+}
+.edit-actions button {
+ padding: 6px 12px;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+}
+.save-btn { background-color: #a3be8c; color: #fff; }
+.cancel-btn { background-color: #eceff4; color: #4c566a; }
diff --git a/app/pages/index.vue b/app/pages/index.vue
index ee553e5..76e00dc 100644
--- a/app/pages/index.vue
+++ b/app/pages/index.vue
@@ -3,7 +3,7 @@
Ваши цели на сегодня
-
Цели обновляются раз в сутки. Бонусы за выполнение целей усиливаются, если посещать страницу ежедневно!
+
Цели обновляются раз в сутки. Получаемые бонусы усиливаются, если посещать сайт ежедневно.
diff --git a/server/api/habits/[id]/index.delete.ts b/server/api/habits/[id]/index.delete.ts
new file mode 100644
index 0000000..bd0602a
--- /dev/null
+++ b/server/api/habits/[id]/index.delete.ts
@@ -0,0 +1,36 @@
+import { getUserIdFromSession } from '../../../utils/auth';
+
+export default defineEventHandler(async (event) => {
+ const userId = await getUserIdFromSession(event);
+ const habitId = Number(event.context.params?.id);
+
+ if (isNaN(habitId)) {
+ throw createError({ statusCode: 400, statusMessage: 'Invalid habit ID.' });
+ }
+
+ // --- Authorization & Deletion ---
+ // First, verify the habit exists and belongs to the user.
+ const habit = await prisma.habit.findUnique({
+ where: {
+ id: habitId,
+ },
+ });
+
+ if (!habit || habit.userId !== userId) {
+ throw createError({ statusCode: 404, statusMessage: 'Habit not found or permission denied.' });
+ }
+
+ // Now, delete the habit
+ await prisma.habit.delete({
+ where: {
+ id: habitId,
+ },
+ });
+
+ // --- Response ---
+ // Send 204 No Content status
+ setResponseStatus(event, 204);
+
+ // Return null or an empty body
+ return null;
+});
diff --git a/server/api/habits/[id]/index.put.ts b/server/api/habits/[id]/index.put.ts
new file mode 100644
index 0000000..ba1edf1
--- /dev/null
+++ b/server/api/habits/[id]/index.put.ts
@@ -0,0 +1,56 @@
+import { getUserIdFromSession } from '../../../utils/auth';
+
+interface HabitDto {
+ id: number;
+ name: string;
+ daysOfWeek: number[];
+}
+
+export default defineEventHandler(async (event): Promise => {
+ const userId = await getUserIdFromSession(event);
+ const habitId = Number(event.context.params?.id);
+ const { name, daysOfWeek } = await readBody(event);
+
+ if (isNaN(habitId)) {
+ throw createError({ statusCode: 400, statusMessage: 'Invalid habit ID.' });
+ }
+
+ // --- Validation ---
+ if (!name || !Array.isArray(daysOfWeek)) {
+ throw createError({ statusCode: 400, statusMessage: 'Invalid input: name and daysOfWeek are required.' });
+ }
+
+ // Sanitize daysOfWeek to ensure it's a unique set of valid numbers
+ const validDays = daysOfWeek.filter(day => typeof day === 'number' && day >= 0 && day <= 6);
+ const sanitizedDays = [...new Set(validDays)].sort();
+
+ // --- Authorization & Update ---
+ // First, verify the habit exists and belongs to the user.
+ const habit = await prisma.habit.findUnique({
+ where: {
+ id: habitId,
+ },
+ });
+
+ if (!habit || habit.userId !== userId) {
+ throw createError({ statusCode: 404, statusMessage: 'Habit not found or permission denied.' });
+ }
+
+ // Now, update the habit
+ const updatedHabit = await prisma.habit.update({
+ where: {
+ id: habitId,
+ },
+ data: {
+ name,
+ daysOfWeek: sanitizedDays,
+ },
+ });
+
+ // Return DTO
+ return {
+ id: updatedHabit.id,
+ name: updatedHabit.name,
+ daysOfWeek: updatedHabit.daysOfWeek as number[],
+ };
+});