Skip to content

Commit 28ae5e5

Browse files
committed
fixed checkboxes
1 parent 9c990b9 commit 28ae5e5

5 files changed

Lines changed: 107 additions & 37 deletions

File tree

src/backend/src/prisma/seed.ts

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3053,10 +3053,10 @@ const performSeed: () => Promise<void> = async () => {
30533053
thomasEmrax,
30543054
ner,
30553055
daysFromNow(30),
3056-
'notes...',
3056+
'Send Google mid-year impact report with project highlights',
30573057
sponsor.sponsorId,
3058-
daysAgo(60),
3059-
thomasEmrax.userId
3058+
daysFromNow(20),
3059+
superman.userId
30603060
);
30613061

30623062
const altiumSponsor = await FinanceServices.createSponsor(
@@ -3242,7 +3242,7 @@ const performSeed: () => Promise<void> = async () => {
32423242
highlightThresholdDays: 14,
32433243
status: 'IN_PROGRESS',
32443244
firstContactMethod: 'OUTBOUND_EMAIL',
3245-
contactorUserId: thomasEmrax.userId,
3245+
contactorUserId: lexLuther.userId,
32463246
contactId: prospectiveContact1.sponsorContactId,
32473247
notes: 'Reached out about potential parts sponsorship for battery systems'
32483248
}
@@ -3256,7 +3256,7 @@ const performSeed: () => Promise<void> = async () => {
32563256
highlightThresholdDays: 10,
32573257
status: 'NO_RESPONSE',
32583258
firstContactMethod: 'OUTBOUND_EMAIL',
3259-
contactorUserId: thomasEmrax.userId,
3259+
contactorUserId: wonderwoman.userId,
32603260
contactId: prospectiveContact2.sponsorContactId,
32613261
notes: 'Sent initial sponsorship proposal, no reply yet'
32623262
}
@@ -3270,7 +3270,7 @@ const performSeed: () => Promise<void> = async () => {
32703270
highlightThresholdDays: 7,
32713271
status: 'IN_PROGRESS',
32723272
firstContactMethod: 'INBOUND_EMAIL',
3273-
contactorUserId: thomasEmrax.userId,
3273+
contactorUserId: flash.userId,
32743274
contactId: prospectiveContact3.sponsorContactId,
32753275
notes: 'They reached out offering software licenses for the team'
32763276
}
@@ -3284,7 +3284,7 @@ const performSeed: () => Promise<void> = async () => {
32843284
highlightThresholdDays: 10,
32853285
status: 'IN_PROGRESS',
32863286
firstContactMethod: 'INBOUND_FORM',
3287-
contactorUserId: thomasEmrax.userId,
3287+
contactorUserId: aquaman.userId,
32883288
contactId: prospectiveContact4.sponsorContactId,
32893289
notes: 'Filled out our sponsorship interest form, interested in providing microcontrollers and dev boards'
32903290
}
@@ -3312,7 +3312,7 @@ const performSeed: () => Promise<void> = async () => {
33123312
highlightThresholdDays: 10,
33133313
status: 'IN_PROGRESS',
33143314
firstContactMethod: 'OTHER',
3315-
contactorUserId: thomasEmrax.userId,
3315+
contactorUserId: batman.userId,
33163316
contactId: prospectiveContact6.sponsorContactId,
33173317
notes: 'Met at local manufacturing expo, interested in providing machining services at reduced cost'
33183318
}
@@ -3326,7 +3326,7 @@ const performSeed: () => Promise<void> = async () => {
33263326
highlightThresholdDays: 14,
33273327
status: 'DECLINED',
33283328
firstContactMethod: 'OUTBOUND_EMAIL',
3329-
contactorUserId: thomasEmrax.userId,
3329+
contactorUserId: superman.userId,
33303330
contactId: prospectiveContact7.sponsorContactId,
33313331
notes: 'Declined for this year, suggested we reapply next fiscal year in September'
33323332
}
@@ -3340,7 +3340,7 @@ const performSeed: () => Promise<void> = async () => {
33403340
highlightThresholdDays: 7,
33413341
status: 'IN_PROGRESS',
33423342
firstContactMethod: 'INBOUND_EMAIL',
3343-
contactorUserId: thomasEmrax.userId,
3343+
contactorUserId: lexLuther.userId,
33443344
contactId: prospectiveContact8.sponsorContactId,
33453345
notes: 'Interested in providing MATLAB/Simulink licenses, scheduling a call next week'
33463346
}
@@ -3363,7 +3363,8 @@ const performSeed: () => Promise<void> = async () => {
33633363
daysFromNow(60),
33643364
'Send McMaster-Carr updated parts list for spring semester',
33653365
mcmasterSponsor.sponsorId,
3366-
daysFromNow(45)
3366+
daysFromNow(45),
3367+
lexLuther.userId
33673368
);
33683369

33693370
await FinanceServices.createSponsorTask(
@@ -3373,7 +3374,7 @@ const performSeed: () => Promise<void> = async () => {
33733374
'Submit Bose quarterly progress report',
33743375
boseSponsor.sponsorId,
33753376
daysAgo(10),
3376-
thomasEmrax.userId
3377+
wonderwoman.userId
33773378
);
33783379

33793380
await FinanceServices.createSponsorTask(
@@ -3383,15 +3384,17 @@ const performSeed: () => Promise<void> = async () => {
33833384
'Prepare annual sponsorship renewal presentation for NEU COE',
33843385
neuSponsor.sponsorId,
33853386
daysFromNow(60),
3386-
thomasEmrax.userId
3387+
batman.userId
33873388
);
33883389

33893390
await FinanceServices.createSponsorTask(
33903391
thomasEmrax,
33913392
ner,
33923393
daysFromNow(7),
33933394
'Send thank-you letter and team photo to Bose',
3394-
boseSponsor.sponsorId
3395+
boseSponsor.sponsorId,
3396+
undefined,
3397+
aquaman.userId
33953398
);
33963399

33973400
// Prospective sponsor tasks
@@ -3401,7 +3404,7 @@ const performSeed: () => Promise<void> = async () => {
34013404
notes: 'Follow up email with Tesla partnership proposal PDF',
34023405
prospectiveSponsorId: teslaProsSpons.prospectiveSponsorId,
34033406
notifyDate: daysFromNow(1),
3404-
assigneeUserId: thomasEmrax.userId
3407+
assigneeUserId: lexLuther.userId
34053408
}
34063409
});
34073410

@@ -3410,7 +3413,7 @@ const performSeed: () => Promise<void> = async () => {
34103413
dueDate: daysFromNow(10),
34113414
notes: 'Schedule demo call with SolidWorks academic team',
34123415
prospectiveSponsorId: solidworksProsSpons.prospectiveSponsorId,
3413-
assigneeUserId: thomasEmrax.userId
3416+
assigneeUserId: flash.userId
34143417
}
34153418
});
34163419

@@ -3420,7 +3423,7 @@ const performSeed: () => Promise<void> = async () => {
34203423
notes: 'Send TI the team roster for university program enrollment',
34213424
prospectiveSponsorId: tiProsSpons.prospectiveSponsorId,
34223425
notifyDate: daysAgo(5),
3423-
assigneeUserId: thomasEmrax.userId,
3426+
assigneeUserId: aquaman.userId,
34243427
done: true
34253428
}
34263429
});
@@ -3430,7 +3433,8 @@ const performSeed: () => Promise<void> = async () => {
34303433
dueDate: daysFromNow(5),
34313434
notes: 'Prepare MathWorks sponsorship tier options document',
34323435
prospectiveSponsorId: mathworksProsSpons.prospectiveSponsorId,
3433-
notifyDate: daysFromNow(2)
3436+
notifyDate: daysFromNow(2),
3437+
assigneeUserId: lexLuther.userId
34343438
}
34353439
});
34363440

@@ -3439,7 +3443,7 @@ const performSeed: () => Promise<void> = async () => {
34393443
dueDate: daysFromNow(14),
34403444
notes: 'Draft MATLAB workshop proposal to show value of partnership',
34413445
prospectiveSponsorId: mathworksProsSpons.prospectiveSponsorId,
3442-
assigneeUserId: thomasEmrax.userId
3446+
assigneeUserId: wonderwoman.userId
34433447
}
34443448
});
34453449

src/backend/src/services/prospective-sponsor.services.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -407,17 +407,19 @@ export default class ProspectiveSponsorServices {
407407
stockDescription?: string,
408408
discountDescription?: string
409409
): Promise<ProspectiveSponsor> {
410-
if (!(await userHasPermission(submitter.userId, organization.organizationId, isHead))) {
411-
throw new AccessDeniedException('Only heads can accept prospective sponsors');
412-
}
413-
414410
const prospectiveSponsor = await prisma.prospective_Sponsor.findUnique({
415411
where: { prospectiveSponsorId, organizationId: organization.organizationId },
416412
include: { contact: true }
417413
});
418414

419415
if (!prospectiveSponsor) throw new NotFoundException('ProspectiveSponsor', prospectiveSponsorId);
420416
if (prospectiveSponsor.dateDeleted) throw new DeletedException('ProspectiveSponsor', prospectiveSponsorId);
417+
418+
const isContactor = prospectiveSponsor.contactorUserId === submitter.userId;
419+
const isUserHead = await userHasPermission(submitter.userId, organization.organizationId, isHead);
420+
if (!isUserHead && !isContactor) {
421+
throw new AccessDeniedException('Only heads or the assigned contactor can accept prospective sponsors');
422+
}
421423
if (prospectiveSponsor.status === Prospective_Sponsor_Status.ACCEPTED) {
422424
throw new HttpException(400, 'This prospective sponsor has already been accepted');
423425
}

src/backend/tests/unit/prospective-sponsor.test.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -891,7 +891,7 @@ describe('Prospective Sponsor Tests', () => {
891891
});
892892

893893
describe('Accept Prospective Sponsor', () => {
894-
it('Fails if user is not a head', async () => {
894+
it('Fails if user is not a head or contactor', async () => {
895895
const head = await createTestUser(batmanAppAdmin, orgId);
896896
const guest = await createTestUser(wonderwomanGuest, orgId);
897897

@@ -920,7 +920,44 @@ describe('Prospective Sponsor Tests', () => {
920920
false,
921921
5000
922922
)
923-
).rejects.toThrow(new AccessDeniedException('Only heads can accept prospective sponsors'));
923+
).rejects.toThrow(new AccessDeniedException('Only heads or the assigned contactor can accept prospective sponsors'));
924+
});
925+
926+
it('Succeeds when the contactor accepts', async () => {
927+
const head = await createTestUser(batmanAppAdmin, orgId);
928+
const contactor = await createTestUser(wonderwomanGuest, orgId);
929+
const joinDate = new Date(2024, 6, 1);
930+
931+
const ps = await ProspectiveSponsorServices.createProspectiveSponsor(
932+
head,
933+
organization,
934+
'Contactor Accept Corp',
935+
ProspectiveSponsorStatus.IN_PROGRESS,
936+
new Date(),
937+
FirstContactMethod.INBOUND_EMAIL,
938+
'Jane Smith',
939+
contactor.userId,
940+
undefined,
941+
'jane@contactorcorp.com'
942+
);
943+
944+
const result = await ProspectiveSponsorServices.acceptProspectiveSponsor(
945+
contactor,
946+
organization,
947+
ps.prospectiveSponsorId,
948+
undefined,
949+
['MONETARY'],
950+
joinDate,
951+
[2024],
952+
false,
953+
3000
954+
);
955+
956+
expect(result.status).toBe(ProspectiveSponsorStatus.ACCEPTED);
957+
const sponsors = await FinanceServices.getAllSponsors(organization);
958+
const createdSponsor = sponsors.find((s) => s.name === 'Contactor Accept Corp');
959+
expect(createdSponsor).toBeDefined();
960+
expect(createdSponsor!.sponsorValue).toBe(3000);
924961
});
925962

926963
it('Fails if prospective sponsor does not exist', async () => {

src/frontend/src/pages/FinancePage/FinanceComponents/SponsorTasksModal.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const taskSchema = yup.object().shape({
2222
sponsorTaskId: yup.string().optional(),
2323
dueDate: yup.date().required('Due date is required'),
2424
notifyDate: yup.date().nullable().optional(),
25-
assignee: yup.string().nullable().optional(),
25+
assigneeUserId: yup.string().nullable().optional(),
2626
notes: yup.string().required('Notes is required'),
2727
done: yup.boolean().optional()
2828
});
@@ -57,7 +57,7 @@ const SponsorTasksModal: React.FC<SponsorTasksModalProps> = ({ onClose, tasks: s
5757
sponsorTaskId: task.sponsorTaskId,
5858
dueDate: task.dueDate ? new Date(task.dueDate) : new Date(),
5959
notifyDate: task.notifyDate ? new Date(task.notifyDate) : undefined,
60-
assignee: task.assignee?.userId || '',
60+
assigneeUserId: task.assignee?.userId || '',
6161
notes: task.notes || '',
6262
done: task.done || false
6363
}));
@@ -79,7 +79,7 @@ const SponsorTasksModal: React.FC<SponsorTasksModalProps> = ({ onClose, tasks: s
7979
const payload = {
8080
dueDate: task.dueDate,
8181
notifyDate: task.notifyDate || undefined,
82-
assigneeUserId: task.assignee || undefined,
82+
assigneeUserId: task.assigneeUserId || undefined,
8383
notes: task.notes,
8484
done: task.done ?? false
8585
};
@@ -134,7 +134,7 @@ const SponsorTasksModal: React.FC<SponsorTasksModalProps> = ({ onClose, tasks: s
134134
append({
135135
dueDate: new Date(),
136136
notifyDate: undefined,
137-
assignee: '',
137+
assigneeUserId: '',
138138
notes: '',
139139
sponsorTaskId: undefined,
140140
done: false

src/frontend/src/pages/FinancePage/SponsorsTable.tsx

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,35 @@ const SponsorsTable = () => {
5252
setIsTasksModalOpen(false);
5353
};
5454

55+
const sponsorToInlinePayload = (sponsor: Sponsor, overrides: Partial<Sponsor>) => ({
56+
sponsorId: sponsor.sponsorId,
57+
name: sponsor.name,
58+
activeStatus: sponsor.activeStatus,
59+
valueTypes: sponsor.valueTypes,
60+
sponsorValue: sponsor.sponsorValue,
61+
joinDate: sponsor.joinDate,
62+
activeYears: sponsor.activeYears,
63+
sponsorTierId: sponsor.tier?.sponsorTierId,
64+
taxExempt: sponsor.taxExempt,
65+
contactName: sponsor.contact.name,
66+
contactEmail: sponsor.contact.email,
67+
contactPhone: sponsor.contact.phone,
68+
contactPosition: sponsor.contact.position,
69+
sponsorTasks: sponsor.sponsorTasks.map((t) => ({
70+
sponsorTaskId: t.sponsorTaskId,
71+
dueDate: t.dueDate,
72+
notifyDate: t.notifyDate,
73+
assigneeUserId: t.assignee?.userId,
74+
notes: t.notes,
75+
done: t.done
76+
})),
77+
discountCode: sponsor.discountCode,
78+
sponsorNotes: sponsor.sponsorNotes,
79+
stockDescription: sponsor.stockDescription,
80+
discountDescription: sponsor.discountDescription,
81+
...overrides
82+
});
83+
5584
const columns = [
5685
{ field: 'name', headerName: 'Sponsor', flex: 1, minWidth: 50 },
5786
{
@@ -66,10 +95,9 @@ const SponsorsTable = () => {
6695
checked={!!p.value}
6796
onClick={async (e: MouseEvent<HTMLElement>) => {
6897
e.stopPropagation();
69-
await editSponsorMutateAsync({
70-
...(p.row as MapRowResult<Sponsor>).raw,
71-
activeStatus: !p.value
72-
} as unknown as Parameters<typeof editSponsorMutateAsync>[0]);
98+
const sponsor = (p.row as MapRowResult<Sponsor>).raw;
99+
if (!sponsor) return;
100+
await editSponsorMutateAsync(sponsorToInlinePayload(sponsor, { activeStatus: !p.value }));
73101
}}
74102
/>
75103
)
@@ -151,10 +179,9 @@ const SponsorsTable = () => {
151179
checked={!!p.value}
152180
onClick={(e: MouseEvent<HTMLElement>) => {
153181
e.stopPropagation();
154-
editSponsorMutateAsync({
155-
...(p.row as MapRowResult<Sponsor>).raw,
156-
taxExempt: !p.value
157-
} as unknown as Parameters<typeof editSponsorMutateAsync>[0]);
182+
const sponsor = (p.row as MapRowResult<Sponsor>).raw;
183+
if (!sponsor) return;
184+
editSponsorMutateAsync(sponsorToInlinePayload(sponsor, { taxExempt: !p.value }));
158185
}}
159186
/>
160187
);

0 commit comments

Comments
 (0)