Skip to content

Commit 6ef89aa

Browse files
authored
[Release] Version 0.2.0 (#337)
* [Improvement] Update donation receipt spacing (#326) * Fix validation schema for other gender field (#327) * Adjust schema to evaluate date at validation time (#328) * [Fix] Make replacement requests clearer (#325) * Add new contributor to seeding script (#330) * ignore the .yarn file for > v2.0.0 (#331) * [Misc] Create initial baseline migration file (#333) * [Doc] Update README with prisma migrate deploy command (#334) * [Fix] Fix replacement request otherGender and lostTimestamp form validations (#335) * [Misc] Add holiday closure banner (#336)
1 parent c8afba7 commit 6ef89aa

File tree

12 files changed

+579
-82
lines changed

12 files changed

+579
-82
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
# dependencies
44
/node_modules
5+
/.yarn*
56
/.pnp
67
.pnp.js
78

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ yarn dev
6969
3. Deploy prisma schema
7070

7171
```bash
72-
npx prisma db push
72+
npx prisma migrate deploy
7373
```
7474

7575
4. Seed database

components/admin/requests/permit-holder-information/Card.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,6 @@ const Card: FC<Props> = props => {
9494
| null;
9595
if (type === 'NEW') {
9696
const validatedData = await permitHolderInformationSchema.validate(permitHolderData);
97-
// TODO: Remove this once schema is updated
98-
validatedData.otherGender = '';
9997

10098
({ data } = await updateNewPermitHolderInformation({
10199
variables: { input: { id: applicationId, ...validatedData } },

components/admin/requests/reason-for-replacement/Form.tsx

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ import NumberField from '@components/form/NumberField';
1313
import RadioGroupField from '@components/form/RadioGroupField';
1414
import TextArea from '@components/form/TextAreaField';
1515
import TextField from '@components/form/TextField';
16-
import { formatDate } from '@lib/utils/date'; // Date formatter util
16+
import { formatDateYYYYMMDDLocal } from '@lib/utils/date'; // Date formatter util
1717
import { ReasonForReplacementFormData } from '@tools/admin/requests/reason-for-replacement';
1818
import { useFormikContext } from 'formik';
19+
import moment from 'moment';
1920

2021
type ReasonForReplacementProps = {
2122
readonly reasonForReplacement: ReasonForReplacementFormData;
@@ -36,9 +37,30 @@ export default function ReasonForReplacementForm({
3637
<Box paddingBottom="24px">
3738
<RadioGroupField name="reasonForReplacement.reason" label="Reason" required>
3839
<Stack>
39-
<Radio value={'LOST'}>{'Lost'}</Radio>
40-
<Radio value={'STOLEN'}>{'Stolen'}</Radio>
41-
<Radio value={'OTHER'}>{'Other'}</Radio>
40+
<Radio
41+
value={'LOST'}
42+
onChange={() => {
43+
setFieldValue('paymentInformation.processingFee', '31');
44+
}}
45+
>
46+
{'Lost'}
47+
</Radio>
48+
<Radio
49+
value={'STOLEN'}
50+
onChange={() => {
51+
setFieldValue('paymentInformation.processingFee', '31');
52+
}}
53+
>
54+
{'Stolen'}
55+
</Radio>
56+
<Radio
57+
value={'OTHER'}
58+
onChange={() => {
59+
setFieldValue('paymentInformation.processingFee', '0');
60+
}}
61+
>
62+
{'Mail Lost'}
63+
</Radio>
4264
</Stack>
4365
</RadioGroupField>
4466
</Box>
@@ -54,7 +76,10 @@ export default function ReasonForReplacementForm({
5476
required
5577
value={
5678
reasonForReplacement.lostTimestamp
57-
? formatDate(new Date(reasonForReplacement.lostTimestamp), true)
79+
? // lostTimestamp is the date in the LOCAL TIMEZONE, in YYYY-MM-DD format
80+
// use moment to get Date object in local timezone as
81+
// Date constructor defaults to UTC when given YYYY-MM-DD string
82+
formatDateYYYYMMDDLocal(moment(reasonForReplacement.lostTimestamp).toDate())
5883
: ''
5984
}
6085
/>
@@ -70,18 +95,21 @@ export default function ReasonForReplacementForm({
7095
<Input
7196
type="time"
7297
value={
73-
new Date(reasonForReplacement.lostTimestamp).toLocaleTimeString('en-US', {
98+
moment(reasonForReplacement.lostTimestamp).toDate().toLocaleTimeString('en-US', {
7499
hour12: false,
75100
hour: '2-digit',
76101
minute: '2-digit',
77102
}) || ''
78103
}
79104
onChange={event => {
80-
const updatedlostTimestamp = new Date(reasonForReplacement.lostTimestamp);
81-
updatedlostTimestamp.setHours(parseInt(event.target.value.substring(0, 2)));
82-
updatedlostTimestamp.setMinutes(parseInt(event.target.value.substring(3, 5)));
105+
const updatedlostTimestamp = moment(reasonForReplacement.lostTimestamp);
106+
updatedlostTimestamp.set('hour', parseInt(event.target.value.substring(0, 2)));
107+
updatedlostTimestamp.set('minute', parseInt(event.target.value.substring(3, 5)));
83108

84-
setFieldValue('reasonForReplacement.lostTimestamp', updatedlostTimestamp);
109+
setFieldValue(
110+
'reasonForReplacement.lostTimestamp',
111+
updatedlostTimestamp.toDate()
112+
);
85113
}}
86114
/>
87115
<FormHelperText color="text.secondary">{'Example: HH:MM AM/PM'}</FormHelperText>

lib/applications/resolvers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1192,7 +1192,7 @@ export const updateNewApplicationGeneralInformation: Resolver<
11921192
const { input } = args;
11931193

11941194
try {
1195-
await requestPermitHolderInformationMutationSchema.validate(input);
1195+
await requestPermitHolderInformationMutationSchema.validate({ type: 'NEW', ...input });
11961196
} catch (err) {
11971197
if (err instanceof ValidationError) {
11981198
return {

lib/applications/validation.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ import {
88
requestPhysicianInformationSchema,
99
} from '@lib/physicians/validation';
1010
import { PaymentType, Province, ReasonForReplacement, ShopifyPaymentStatus } from '@prisma/client';
11-
import { bool, date, mixed, number, object, string } from 'yup';
11+
import { bool, date, lazy, mixed, number, object, string } from 'yup';
1212
import {
1313
AccessibleConvertedVanLoadingMethod,
1414
RequiresWiderParkingSpaceReason,
1515
} from '@lib/graphql/types';
1616
import { monetaryValueRegex, phoneNumberRegex, postalCodeRegex } from '@lib/utils/validation';
17+
import moment from 'moment';
1718

1819
/**
1920
* Additional Questions form validation schema
@@ -215,13 +216,16 @@ export const reasonForReplacementFormSchema = object({
215216
.default(null)
216217
.when('reason', {
217218
is: 'LOST',
218-
then: date()
219-
.transform((_value, originalValue) => {
220-
return new Date(originalValue);
221-
})
222-
.typeError('Please enter date APP was lost')
223-
.max(new Date(), 'Date must be in the past')
224-
.required('Please enter date APP was lost'),
219+
then: lazy(() =>
220+
date()
221+
.transform((_value, originalValue) => {
222+
// convert YYYY-MM-DD string in local timezone to a Date object in UTC
223+
return moment.utc(moment(originalValue).toDate()).toDate();
224+
})
225+
.typeError('Please enter date APP was lost')
226+
.max(new Date(), 'Date must be in the past')
227+
.required('Please enter date APP was lost')
228+
),
225229
otherwise: date()
226230
.transform(_ => null)
227231
.nullable(),

lib/invoices/utils.ts

Lines changed: 64 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -404,57 +404,74 @@ const donationPdfDefinition = (input: {
404404
pageBreak: 'before',
405405
text: [
406406
{ text: 'RICHMOND CENTRE FOR DISABILITY', style: 'header' },
407-
'\n\n',
407+
'\n',
408408
{
409409
text: `Official Donation Receipt for Income Tax Purposes - ${dateIssued.getFullYear()}`,
410-
style: 'subheaderDonation',
410+
style: 'subheader',
411411
},
412412
],
413413
},
414+
414415
{
415416
columns: [
416417
{
417-
table: {
418-
heights: 20,
419-
body: [
420-
[
421-
{ text: 'Tax Receipt #:' },
422-
`PPD_${dateIssued.getFullYear()}${dateIssued.getMonth()}${dateIssued.getDate()}_${appNumber}`,
423-
],
424-
[
425-
{ text: 'Donated by:' },
426-
{
427-
text: [
428-
`${applicantName}\n`,
429-
`${address.addressLine2 ? `${address.addressLine2} - ` : ''}${
430-
address.addressLine1
431-
}\n`,
432-
`${address.city} ${address.province} ${formatPostalCode(address.postalCode)}`,
418+
stack: [
419+
{
420+
table: {
421+
heights: 18,
422+
body: [
423+
[
424+
{ text: 'Tax Receipt #:' },
425+
`PPD_${dateIssued.getFullYear()}${dateIssued.getMonth()}${dateIssued.getDate()}_${appNumber}`,
433426
],
434-
fontSize: 12,
435-
lineHeight: 1.5,
436-
},
437-
],
438-
[{ text: '' }, ''],
439-
[{ text: '' }, ''],
440-
[{ text: '' }, ''],
441-
[{ text: 'Email:' }, nonNullEmail],
442-
[{ text: 'Date Receipt Issued:' }, formatDateYYYYMMDD(dateIssued)],
443-
[{ text: 'Location Receipt Issued:' }, 'Richmond, BC'],
444-
[{ text: 'Authorized Signature:' }, { image: 'signature', width: 150 }],
445-
],
446-
},
447-
layout: 'noBorders',
448-
margin: [0, 0, 20, 0],
427+
[
428+
{ text: 'Donated by:' },
429+
{
430+
text: [
431+
`${applicantName}\n`,
432+
`${address.addressLine2 ? `${address.addressLine2} - ` : ''}${
433+
address.addressLine1
434+
}\n`,
435+
`${address.city} ${address.province} ${formatPostalCode(
436+
address.postalCode
437+
)}`,
438+
],
439+
lineHeight: 1.4,
440+
},
441+
],
442+
],
443+
},
444+
layout: 'noBorders',
445+
margin: [0, 0, 0, 40],
446+
},
447+
{
448+
text: [`Email: ${nonNullEmail}`],
449+
margin: [0, 0, 0, 8],
450+
},
451+
{
452+
table: {
453+
heights: 18,
454+
body: [
455+
[{ text: 'Date Receipt Issued:' }, formatDateYYYYMMDD(dateIssued)],
456+
[{ text: 'Location Receipt Issued:' }, 'Richmond, BC'],
457+
],
458+
},
459+
margin: [0, 0, 0, 15],
460+
layout: 'noBorders',
461+
},
462+
{ image: 'signature', width: 200, margin: [0, 0, 0, 5] },
463+
{ text: 'Authorized Signature:' },
464+
],
449465
},
466+
450467
{
451468
table: {
452-
heights: 20,
469+
heights: 18,
453470
body: [
454471
[{ text: 'Date Donation Received:' }, formatDateYYYYMMDD(dateDonationRecevied)],
455472
[{ text: 'Donor Number:' }, `P${appNumber}`],
456473
[{ text: 'Total Amount:' }, `$${donationAmount.toString()}`],
457-
[{ text: 'Value of Product / Services:' }, ''],
474+
[{ text: 'Value of Product / Services:\n\n' }, ''],
458475
[
459476
{ text: 'Eligible Amount of Donation for Tax Purposes:' },
460477
`$${donationAmount.toString()}`,
@@ -469,26 +486,26 @@ const donationPdfDefinition = (input: {
469486
'Address of Appraiser:\n\n',
470487
],
471488
},
472-
{ image: 'stamp', width: 85 },
489+
{ image: 'stamp', width: 80 },
473490
],
474491
],
475492
},
476493
layout: 'noBorders',
477-
margin: [20, 0, 0, 0],
494+
margin: [15, 0, 0, 0],
478495
},
479496
],
480-
margin: [0, 35, 0, 25],
497+
margin: [0, 25, 0, 0],
481498
},
482499
{
483500
text: [
484-
`Dear ${applicantName}\n\n`,
501+
`Dear ${applicantName}\n\n\n`,
485502
'On behalf of the Richmond Centre for Disability (RCD), we would like to extend our sincere and\n',
486503
'heartfelt thanks and appreciation for your donation. Please find your official tax receipt enclosed.\n\n',
487504
'Through RCD services and support, we have seen the lives of people with disabilities and their\n',
488505
'families changed for the better. Your generosity does make a difference in the delivery of much\n',
489506
'coveted services to people with disabilities. The work being undertaken through the RCD is only\n',
490-
'possible because of caring people like you.\n\n',
491-
'Thank you again for your valued support.\n\n',
507+
'possible because of caring people like you.\n\n\n',
508+
'Thank you again for your valued support.\n\n\n',
492509
'Sincerely,\n\n\n',
493510
'RICHMOND CENTRE FOR DISABILITY\n',
494511
'(Charity Number: 88832-8432-RR0001)\n',
@@ -498,35 +515,32 @@ const donationPdfDefinition = (input: {
498515
'Website:www.rcdrichmond.org\n',
499516
],
500517
margin: [0, 15, 0, 0],
501-
fontSize: 12,
502518
},
503519
]),
504520
styles: {
505521
header: {
506-
fontSize: 28,
522+
fontSize: 25.5,
507523
bold: true,
508524
alignment: 'center',
525+
lineHeight: 1.5,
509526
},
510527
tableHeader: {
511528
bold: true,
512529
alignment: 'center',
513530
},
514531
subheader: {
515-
fontSize: 20,
516-
bold: false,
517-
alignment: 'center',
518-
},
519-
subheaderDonation: {
520-
fontSize: 19,
532+
fontSize: 17.5,
521533
alignment: 'center',
522534
},
523535
footer: {
524-
fontSize: 8,
536+
fontSize: 7.5,
525537
alignment: 'center',
526538
},
527539
},
528540
defaultStyle: {
529541
font: 'Helvetica',
542+
fontSize: 11,
543+
lineHeight: 1.2,
530544
},
531545
images: {
532546
rcd: 'public/assets/logo.png',

lib/physicians/validation.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
import { phoneNumberRegex, postalCodeRegex } from '@lib/utils/validation';
22
import { MobilityAid, PatientCondition, PermitType } from '@prisma/client';
3-
import { date, mixed, object, string, array, number } from 'yup';
3+
import { date, lazy, mixed, object, string, array, number } from 'yup';
44

55
/**
66
* Validation schema for physician assessment form
77
*/
88
export const physicianAssessmentSchema = object({
99
disability: string().required('Please enter a disabling condition'),
10-
disabilityCertificationDate: date()
11-
.transform((_value, originalValue) => {
12-
return new Date(originalValue);
13-
})
14-
.max(new Date(), 'Date must be in the past')
15-
.required('Please enter a valid certification date'),
10+
disabilityCertificationDate: lazy(() =>
11+
date()
12+
.transform((_value, originalValue) => {
13+
return new Date(originalValue);
14+
})
15+
.max(new Date(), 'Date must be in the past')
16+
.required('Please enter a valid certification date')
17+
),
1618
patientCondition: array(
1719
mixed<PatientCondition>()
1820
.oneOf(Object.values(PatientCondition))

pages/index.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@ export default function Landing() {
2222

2323
return (
2424
<Layout>
25-
{Date.now() < new Date('2023-11-23T06:00:00.000Z').getTime() && (
25+
{Date.now() < new Date('2024-01-02T08:00:00.000Z').getTime() && (
2626
<GridItem colSpan={12} colStart={1}>
2727
<Alert status="warning" variant="top-accent">
2828
<AlertIcon />
2929
<AlertDescription>
30-
Please note that this site will be offline for planned maintenance on Nov 22, 2023
31-
from 7:00pm to 10:00pm PST. We apologize for any inconvenience.
30+
Please note that the RCD office will be closed between Dec 18 and Jan 1 and will
31+
resume regular business hours on Jan 2. We will process applications received during
32+
the holidays, but all other services will be unavailable. We apologize for any
33+
inconvenience.
3234
</AlertDescription>
3335
</Alert>
3436
</GridItem>

0 commit comments

Comments
 (0)