feat: Add dueDate (date+time) to notes and update reminders to datetime
- Add dueDate timestamp field to notes schema - Update note validators to accept dueDate - Update note service to handle dueDate in CRUD operations - Fix company and project controllers to pass dueDate - Fix route validations to include dueDate field 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -208,11 +208,12 @@ export const addCompanyNote = async (req, res, next) => {
|
||||
try {
|
||||
const userId = req.userId;
|
||||
const { companyId } = req.params;
|
||||
const { content } = req.body;
|
||||
const { content, dueDate } = req.body;
|
||||
|
||||
const note = await noteService.createNote(userId, {
|
||||
content,
|
||||
companyId,
|
||||
dueDate,
|
||||
});
|
||||
|
||||
res.status(201).json({
|
||||
@@ -232,10 +233,11 @@ export const addCompanyNote = async (req, res, next) => {
|
||||
export const updateCompanyNote = async (req, res, next) => {
|
||||
try {
|
||||
const { noteId } = req.params;
|
||||
const { content } = req.body;
|
||||
const { content, dueDate } = req.body;
|
||||
|
||||
const note = await noteService.updateNote(noteId, {
|
||||
content,
|
||||
dueDate,
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
|
||||
@@ -165,12 +165,12 @@ export const addProjectNote = async (req, res, next) => {
|
||||
try {
|
||||
const userId = req.userId;
|
||||
const { projectId } = req.params;
|
||||
const { content, reminderAt } = req.body;
|
||||
const { content, dueDate } = req.body;
|
||||
|
||||
const note = await noteService.createNote(userId, {
|
||||
content,
|
||||
projectId,
|
||||
reminderDate: reminderAt, // Map reminderAt to reminderDate
|
||||
dueDate,
|
||||
});
|
||||
|
||||
res.status(201).json({
|
||||
@@ -190,11 +190,11 @@ export const addProjectNote = async (req, res, next) => {
|
||||
export const updateProjectNote = async (req, res, next) => {
|
||||
try {
|
||||
const { noteId } = req.params;
|
||||
const { content, reminderAt } = req.body;
|
||||
const { content, dueDate } = req.body;
|
||||
|
||||
const note = await noteService.updateNote(noteId, {
|
||||
content,
|
||||
reminderDate: reminderAt, // Map reminderAt to reminderDate
|
||||
dueDate,
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
|
||||
@@ -210,7 +210,7 @@ export const todoUsers = pgTable('todo_users', {
|
||||
todoUserUnique: unique('todo_user_unique').on(table.todoId, table.userId),
|
||||
}));
|
||||
|
||||
// Notes table - poznámky (bez reminder funkcionalít)
|
||||
// Notes table - poznámky s voliteľným dátumom a časom splnenia
|
||||
export const notes = pgTable('notes', {
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
title: text('title'),
|
||||
@@ -219,6 +219,7 @@ export const notes = pgTable('notes', {
|
||||
projectId: uuid('project_id').references(() => projects.id, { onDelete: 'cascade' }), // alebo projektu
|
||||
todoId: uuid('todo_id').references(() => todos.id, { onDelete: 'cascade' }), // alebo todo
|
||||
contactId: uuid('contact_id').references(() => contacts.id, { onDelete: 'cascade' }), // alebo kontaktu
|
||||
dueDate: timestamp('due_date'), // voliteľný dátum a čas splnenia (24h formát)
|
||||
createdBy: uuid('created_by').references(() => users.id, { onDelete: 'set null' }),
|
||||
createdAt: timestamp('created_at').defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at').defaultNow().notNull(),
|
||||
|
||||
@@ -83,6 +83,7 @@ router.post(
|
||||
validateParams(z.object({ companyId: z.string().uuid() })),
|
||||
validateBody(z.object({
|
||||
content: z.string().min(1),
|
||||
dueDate: z.string().optional().or(z.literal('')),
|
||||
})),
|
||||
companyController.addCompanyNote
|
||||
);
|
||||
@@ -96,6 +97,7 @@ router.patch(
|
||||
})),
|
||||
validateBody(z.object({
|
||||
content: z.string().min(1).optional(),
|
||||
dueDate: z.string().optional().or(z.literal('').or(z.null())),
|
||||
})),
|
||||
companyController.updateCompanyNote
|
||||
);
|
||||
|
||||
@@ -66,7 +66,7 @@ router.post(
|
||||
validateParams(z.object({ projectId: z.string().uuid() })),
|
||||
validateBody(z.object({
|
||||
content: z.string().min(1),
|
||||
reminderAt: z.string().optional().or(z.literal('')),
|
||||
dueDate: z.string().optional().or(z.literal('')),
|
||||
})),
|
||||
projectController.addProjectNote
|
||||
);
|
||||
@@ -80,7 +80,7 @@ router.patch(
|
||||
})),
|
||||
validateBody(z.object({
|
||||
content: z.string().min(1).optional(),
|
||||
reminderAt: z.string().optional().or(z.literal('').or(z.null())),
|
||||
dueDate: z.string().optional().or(z.literal('').or(z.null())),
|
||||
})),
|
||||
projectController.updateProjectNote
|
||||
);
|
||||
|
||||
@@ -20,6 +20,7 @@ export const getAllNotes = async (filters = {}) => {
|
||||
projectId: notes.projectId,
|
||||
todoId: notes.todoId,
|
||||
contactId: notes.contactId,
|
||||
dueDate: notes.dueDate,
|
||||
createdBy: notes.createdBy,
|
||||
createdAt: notes.createdAt,
|
||||
updatedAt: notes.updatedAt,
|
||||
@@ -86,7 +87,7 @@ export const getNoteById = async (noteId) => {
|
||||
* Create new note
|
||||
*/
|
||||
export const createNote = async (userId, data) => {
|
||||
const { title, content, companyId, projectId, todoId, contactId } = data;
|
||||
const { title, content, companyId, projectId, todoId, contactId, dueDate } = data;
|
||||
|
||||
// Verify company exists if provided
|
||||
if (companyId) {
|
||||
@@ -149,6 +150,7 @@ export const createNote = async (userId, data) => {
|
||||
projectId: projectId || null,
|
||||
todoId: todoId || null,
|
||||
contactId: contactId || null,
|
||||
dueDate: dueDate ? new Date(dueDate) : null,
|
||||
createdBy: userId,
|
||||
})
|
||||
.returning();
|
||||
@@ -162,7 +164,7 @@ export const createNote = async (userId, data) => {
|
||||
export const updateNote = async (noteId, data) => {
|
||||
const note = await getNoteById(noteId);
|
||||
|
||||
const { title, content, companyId, projectId, todoId, contactId } = data;
|
||||
const { title, content, companyId, projectId, todoId, contactId, dueDate } = data;
|
||||
|
||||
// Verify company exists if being changed
|
||||
if (companyId !== undefined && companyId !== null && companyId !== note.companyId) {
|
||||
@@ -216,6 +218,12 @@ export const updateNote = async (noteId, data) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Spracovanie dueDate - konverzia na Date objekt alebo null
|
||||
let parsedDueDate = note.dueDate;
|
||||
if (dueDate !== undefined) {
|
||||
parsedDueDate = dueDate ? new Date(dueDate) : null;
|
||||
}
|
||||
|
||||
const [updated] = await db
|
||||
.update(notes)
|
||||
.set({
|
||||
@@ -225,6 +233,7 @@ export const updateNote = async (noteId, data) => {
|
||||
projectId: projectId !== undefined ? projectId : note.projectId,
|
||||
todoId: todoId !== undefined ? todoId : note.todoId,
|
||||
contactId: contactId !== undefined ? contactId : note.contactId,
|
||||
dueDate: parsedDueDate,
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.where(eq(notes.id, noteId))
|
||||
@@ -258,6 +267,7 @@ export const getNotesByCompanyId = async (companyId) => {
|
||||
projectId: notes.projectId,
|
||||
todoId: notes.todoId,
|
||||
contactId: notes.contactId,
|
||||
dueDate: notes.dueDate,
|
||||
createdBy: notes.createdBy,
|
||||
createdAt: notes.createdAt,
|
||||
updatedAt: notes.updatedAt,
|
||||
@@ -286,6 +296,7 @@ export const getNotesByProjectId = async (projectId) => {
|
||||
projectId: notes.projectId,
|
||||
todoId: notes.todoId,
|
||||
contactId: notes.contactId,
|
||||
dueDate: notes.dueDate,
|
||||
createdBy: notes.createdBy,
|
||||
createdAt: notes.createdAt,
|
||||
updatedAt: notes.updatedAt,
|
||||
|
||||
@@ -81,7 +81,7 @@ export const updateTodoSchema = z.object({
|
||||
dueDate: z.string().optional().or(z.literal('').or(z.null())),
|
||||
});
|
||||
|
||||
// Note validators (without reminder functionality)
|
||||
// Note validators (s voliteľným dueDate pre dátum a čas)
|
||||
export const createNoteSchema = z.object({
|
||||
title: z.string().max(255).optional(),
|
||||
content: z
|
||||
@@ -94,6 +94,7 @@ export const createNoteSchema = z.object({
|
||||
projectId: z.string().uuid('Neplatný formát project ID').optional().or(z.literal('')),
|
||||
todoId: z.string().uuid('Neplatný formát todo ID').optional().or(z.literal('')),
|
||||
contactId: z.string().uuid('Neplatný formát contact ID').optional().or(z.literal('')),
|
||||
dueDate: z.string().optional().or(z.literal('')), // ISO string s dátumom a časom (24h formát)
|
||||
});
|
||||
|
||||
export const updateNoteSchema = z.object({
|
||||
@@ -103,6 +104,7 @@ export const updateNoteSchema = z.object({
|
||||
projectId: z.string().uuid('Neplatný formát project ID').optional().or(z.literal('').or(z.null())),
|
||||
todoId: z.string().uuid('Neplatný formát todo ID').optional().or(z.literal('').or(z.null())),
|
||||
contactId: z.string().uuid('Neplatný formát contact ID').optional().or(z.literal('').or(z.null())),
|
||||
dueDate: z.string().optional().or(z.literal('').or(z.null())), // ISO string s dátumom a časom (24h formát)
|
||||
});
|
||||
|
||||
// Company reminder validators (with dueDate)
|
||||
|
||||
Reference in New Issue
Block a user