Skip to content

Commit 112dbf5

Browse files
committed
feat(Tasks): add task management functionality with modal for adding tasks and user assignment
1 parent 5e8a594 commit 112dbf5

File tree

2 files changed

+245
-60
lines changed

2 files changed

+245
-60
lines changed

src/routes/(app)/app/accounts/[accountId]/+page.server.js

Lines changed: 94 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@ import prisma from '$lib/prisma';
55
export async function load({ params, url }) {
66
try {
77
const accountId = params.accountId;
8-
8+
99
// Fetch account details
1010
const account = await prisma.account.findUnique({
1111
where: {
1212
id: accountId
1313
}
1414
});
15-
15+
1616
if (!account) {
1717
throw error(404, 'Account not found');
1818
}
19-
19+
2020
// Fetch account contacts
2121
const contactRelationships = await prisma.accountContactRelationship.findMany({
2222
where: {
@@ -26,21 +26,21 @@ export async function load({ params, url }) {
2626
contact: true
2727
}
2828
});
29-
29+
3030
// Format contacts with isPrimary flag
3131
const contacts = contactRelationships.map(rel => ({
3232
...rel.contact,
3333
isPrimary: rel.isPrimary,
3434
role: rel.role
3535
}));
36-
36+
3737
// Fetch account opportunities
3838
const opportunities = await prisma.opportunity.findMany({
3939
where: {
4040
accountId: accountId
4141
}
4242
});
43-
43+
4444
// Fetch account comments/notes
4545
const comments = await prisma.comment.findMany({
4646
where: {
@@ -62,14 +62,14 @@ export async function load({ params, url }) {
6262
if (url.searchParams.get('commentsOnly') === '1') {
6363
return new Response(JSON.stringify({ comments }), { headers: { 'Content-Type': 'application/json' } });
6464
}
65-
65+
6666
// Fetch account quotes
6767
const quotes = await prisma.quote.findMany({
6868
where: {
6969
accountId: accountId
7070
}
7171
});
72-
72+
7373
// Fetch account tasks
7474
const tasks = await prisma.task.findMany({
7575
where: {
@@ -84,14 +84,24 @@ export async function load({ params, url }) {
8484
}
8585
}
8686
});
87-
87+
8888
// Fetch account cases
8989
const cases = await prisma.case.findMany({
9090
where: {
9191
accountId: accountId
9292
}
9393
});
94-
94+
95+
// Load users in the same organization for assignment
96+
const users = await prisma.user.findMany({
97+
where: {
98+
organizations: {
99+
some: { organizationId: account.organizationId }
100+
}
101+
},
102+
select: { id: true, name: true, email: true }
103+
});
104+
95105
return {
96106
account,
97107
contacts,
@@ -100,6 +110,7 @@ export async function load({ params, url }) {
100110
quotes,
101111
tasks,
102112
cases,
113+
users,
103114
meta: {
104115
title: account.name,
105116
description: `Account details for ${account.name}`
@@ -116,19 +127,19 @@ export const actions = {
116127
closeAccount: async ({ params, request, locals }) => {
117128
try {
118129
const user = locals.user;
119-
130+
120131
if (!user) {
121132
return fail(401, { success: false, message: 'Unauthorized' });
122133
}
123-
134+
124135
const { accountId } = params;
125136
const formData = await request.formData();
126137
const closureReason = formData.get('closureReason')?.toString();
127-
138+
128139
if (!closureReason) {
129140
return fail(400, { success: false, message: 'Please provide a reason for closing this account' });
130141
}
131-
142+
132143
// Fetch the account to verify it exists
133144
const account = await prisma.account.findUnique({
134145
where: { id: accountId },
@@ -139,32 +150,32 @@ export const actions = {
139150
ownerId: true
140151
}
141152
});
142-
153+
143154
if (!account) {
144155
return fail(404, { success: false, message: 'Account not found' });
145156
}
146-
157+
147158
if (account.closedAt) {
148159
return fail(400, { success: false, message: 'Account is already closed' });
149160
}
150-
161+
151162
// Check user permissions (must be the owner, a sales manager, or admin)
152163
const userOrg = await prisma.userOrganization.findFirst({
153164
where: {
154165
userId: user.id,
155166
organizationId: account.organizationId
156167
}
157168
});
158-
159-
const hasPermission =
160-
user.id === account.ownerId ||
161-
userOrg?.role === 'ADMIN' ||
169+
170+
const hasPermission =
171+
user.id === account.ownerId ||
172+
userOrg?.role === 'ADMIN' ||
162173
userOrg?.role === 'SALES_MANAGER';
163-
174+
164175
if (!hasPermission) {
165176
return fail(403, { success: false, message: 'Permission denied. Only account owners, sales managers, or admins can close accounts.' });
166177
}
167-
178+
168179
// Update the account to mark it as closed
169180
const updatedAccount = await prisma.account.update({
170181
where: { id: accountId },
@@ -173,7 +184,7 @@ export const actions = {
173184
closureReason
174185
}
175186
});
176-
187+
177188
// Log this action in the audit log
178189
await prisma.auditLog.create({
179190
data: {
@@ -188,24 +199,24 @@ export const actions = {
188199
ipAddress: request.headers.get('x-forwarded-for') || 'unknown'
189200
}
190201
});
191-
202+
192203
return { success: true };
193204
} catch (error) {
194205
console.error('Error closing account:', error);
195206
return fail(500, { success: false, message: 'An unexpected error occurred' });
196207
}
197208
},
198-
209+
199210
reopenAccount: async ({ params, request, locals }) => {
200211
try {
201212
const user = locals.user;
202-
213+
203214
if (!user) {
204215
return fail(401, { success: false, message: 'Unauthorized' });
205216
}
206-
217+
207218
const { accountId } = params;
208-
219+
209220
// Fetch the account to verify it exists
210221
const account = await prisma.account.findUnique({
211222
where: { id: accountId },
@@ -217,38 +228,38 @@ export const actions = {
217228
ownerId: true
218229
}
219230
});
220-
231+
221232
if (!account) {
222233
return fail(404, { success: false, message: 'Account not found' });
223234
}
224-
235+
225236
if (!account.closedAt) {
226237
return fail(400, { success: false, message: 'Account is not closed' });
227238
}
228-
239+
229240
// Check user permissions (must be the owner, a sales manager, or admin)
230241
const userOrg = await prisma.userOrganization.findFirst({
231242
where: {
232243
userId: user.id,
233244
organizationId: account.organizationId
234245
}
235246
});
236-
237-
const hasPermission =
238-
user.id === account.ownerId ||
239-
userOrg?.role === 'ADMIN' ||
247+
248+
const hasPermission =
249+
user.id === account.ownerId ||
250+
userOrg?.role === 'ADMIN' ||
240251
userOrg?.role === 'SALES_MANAGER';
241-
252+
242253
if (!hasPermission) {
243254
return fail(403, { success: false, message: 'Permission denied. Only account owners, sales managers, or admins can reopen accounts.' });
244255
}
245-
256+
246257
// Save the old values for the audit log
247258
const oldValues = {
248259
closedAt: account.closedAt,
249260
closureReason: account.closureReason
250261
};
251-
262+
252263
// Update the account to mark it as reopened
253264
const updatedAccount = await prisma.account.update({
254265
where: { id: accountId },
@@ -257,7 +268,7 @@ export const actions = {
257268
closureReason: null
258269
}
259270
});
260-
271+
261272
// Log this action in the audit log
262273
await prisma.auditLog.create({
263274
data: {
@@ -272,7 +283,7 @@ export const actions = {
272283
ipAddress: request.headers.get('x-forwarded-for') || 'unknown'
273284
}
274285
});
275-
286+
276287
return { success: true };
277288
} catch (error) {
278289
console.error('Error reopening account:', error);
@@ -372,7 +383,8 @@ export const actions = {
372383
}
373384
},
374385

375-
comment: async ({ request, params }) => {
386+
comment: async ({ request, params, locals }) => {
387+
const user = locals.user;
376388
// Fallback: fetch account to get organizationId
377389
const account = await prisma.account.findUnique({
378390
where: { id: params.accountId },
@@ -396,5 +408,45 @@ export const actions = {
396408
}
397409
});
398410
return { success: true };
411+
},
412+
413+
addTask: async ({ params, request, locals }) => {
414+
try {
415+
const user = locals.user;
416+
const org = locals.org;
417+
if (!user || !org) {
418+
return fail(401, { success: false, message: 'Unauthorized' });
419+
}
420+
const { accountId } = params;
421+
const formData = await request.formData();
422+
const subject = formData.get('subject')?.toString().trim();
423+
const description = formData.get('description')?.toString() || '';
424+
const dueDateRaw = formData.get('dueDate');
425+
const dueDate = dueDateRaw ? new Date(dueDateRaw.toString()) : null;
426+
const priority = formData.get('priority')?.toString() || 'Normal';
427+
if (!subject) {
428+
return fail(400, { success: false, message: 'Subject is required.' });
429+
}
430+
// If no ownerId is provided, default to current user
431+
// if (!ownerId) ownerId = user.id;
432+
console.log(user.id, org.id);
433+
const task = await prisma.task.create({
434+
data: {
435+
subject,
436+
description,
437+
dueDate,
438+
priority,
439+
status: 'Open',
440+
createdBy: { connect: { id: user.id } },
441+
account: { connect: { id: accountId } },
442+
owner: { connect: { id: user.id } },
443+
organization: { connect: { id: org.id } },
444+
}
445+
});
446+
return { success: true, message: 'Task added successfully.', task };
447+
} catch (err) {
448+
console.error('Error adding task:', err);
449+
return fail(500, { success: false, message: 'Failed to add task.' });
450+
}
399451
}
400452
};

0 commit comments

Comments
 (0)