From fecc2ad702ee477bde6126ec11804f38a24ef18c Mon Sep 17 00:00:00 2001 From: Shannon Clarke Date: Mon, 22 Dec 2025 13:32:32 -0400 Subject: [PATCH 1/4] chore: update textbook grant schema --- schemas/primary-school-textbook-grant.json | 200 +++++++-------------- 1 file changed, 63 insertions(+), 137 deletions(-) diff --git a/schemas/primary-school-textbook-grant.json b/schemas/primary-school-textbook-grant.json index bd40b52..360a20e 100644 --- a/schemas/primary-school-textbook-grant.json +++ b/schemas/primary-school-textbook-grant.json @@ -71,20 +71,66 @@ ] }, { - "name": "applicant", + "name": "guardian", "type": "object", + "label": "Guardian Information", "required": true, "fields": [ { - "name": "title", + "name": "firstName", + "type": "string", + "label": "Guardian First Name", + "required": true, + "validations": { + "min": 2, + "max": 50 + } + }, + { + "name": "lastName", "type": "string", - "label": "Title", + "label": "Guardian Last Name", "required": true, "validations": { - "regex": "^(mr|ms|mrs)$", - "message": "Must select a valid title" + "min": 2, + "max": 50 } }, + { + "name": "idNumber", + "type": "string", + "label": "Guardian ID Number", + "required": true, + "validations": { + "min": 2, + "max": 50 + } + }, + { + "name": "passportNumber", + "type": "string", + "label": "Passport Number", + "required": false, + "validations": { + "message": "Passport number must be at least 6 characters" + } + }, + { + "name": "tamisNumber", + "type": "string", + "label": "TAMIS Number", + "required": false, + "validations": { + "message": "Tamis must be 10-15 digits" + } + } + ] + }, + { + "name": "applicant", + "type": "object", + "required": true, + "fields": [ { "name": "firstName", "type": "string", @@ -193,136 +239,7 @@ } ] }, - { - "name": "guardianOrParentRelationship", - "type": "string", - "label": "Are you the parent or guardian?", - "required": true, - "validations": { - "regex": "^(yes|no)$", - "message": "Must select an option" - } - }, - { - "name": "guardian", - "type": "object", - "label": "Guardian Information", - "required": true, - "fields": [ - { - "name": "title", - "type": "string", - "label": "Title", - "required": false, - "validations": { - "max": 10 - } - }, - { - "name": "firstName", - "type": "string", - "label": "Guardian First Name", - "required": true, - "validations": { - "min": 2, - "max": 50 - } - }, - { - "name": "middleName", - "type": "string", - "label": "Guardian Middle Name", - "required": false, - "validations": { - "max": 50 - } - }, - { - "name": "lastName", - "type": "string", - "label": "Guardian Last Name", - "required": true, - "validations": { - "min": 2, - "max": 50 - } - }, - { - "name": "idNumber", - "type": "string", - "label": "Guardian ID Number", - "required": true, - "validations": { - "min": 2, - "max": 50 - } - }, - { - "name": "gender", - "type": "string", - "label": "Guardian Gender", - "required": false - }, - { - "name": "relationship", - "type": "string", - "label": "Relationship to Student", - "required": true, - "validations": { - "max": 50 - } - }, - { - "name": "email", - "type": "email", - "label": "Guardian Email Address", - "required": false - } - ] - }, - { - "name": "contact", - "type": "object", - "label": "Contact Information", - "required": true, - "fields": [ - { - "name": "addressLine1", - "type": "string", - "label": "Address Line 1", - "required": true, - "validations": { - "min": 5, - "max": 200 - } - }, - { - "name": "addressLine2", - "type": "string", - "label": "Address Line 2", - "required": false, - "validations": { - "max": 200 - } - }, - { - "name": "parish", - "type": "string", - "label": "Parish", - "required": true - }, - { - "name": "telephoneNumber", - "type": "string", - "label": "Telephone Number", - "required": true, - "validations": { - "regex": "^\\+?[0-9]{10,15}$", - "message": "Telephone number must be 10-15 digits" - } - } - ] - }, + { "name": "bankAccount", "type": "object", @@ -352,9 +269,18 @@ } }, { - "name": "branchLocation", + "name": "branchName", + "type": "string", + "label": "Branch Name", + "required": true, + "validations": { + "max": 100 + } + }, + { + "name": "branchCode", "type": "string", - "label": "Branch Location", + "label": "Branch Coe", "required": true, "validations": { "max": 100 From ad1715d592e7d251ac351aa54f94d0617e0f83b3 Mon Sep 17 00:00:00 2001 From: Shannon Clarke Date: Wed, 24 Dec 2025 16:07:08 -0400 Subject: [PATCH 2/4] chore: set vscode project formatting options --- .vscode/settings.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9cd0e03 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + } +} From 281ccb68bd5342252109ac1721b02edfad25e163 Mon Sep 17 00:00:00 2001 From: Shannon Clarke Date: Wed, 24 Dec 2025 16:07:24 -0400 Subject: [PATCH 3/4] chore: allow local database connection --- src/database/datasource.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/database/datasource.ts b/src/database/datasource.ts index 8fa8009..efd0c25 100644 --- a/src/database/datasource.ts +++ b/src/database/datasource.ts @@ -5,9 +5,12 @@ import { config } from 'dotenv'; // Load environment variables config(); +const dbHost = process.env.DB_HOST || 'localhost'; +const isLocalDatabase = dbHost === 'localhost' || dbHost === '127.0.0.1'; + export const dataSource = new DataSource({ type: 'postgres', - host: process.env.DB_HOST || 'localhost', + host: dbHost, port: parseInt(process.env.DB_PORT, 10) || 5432, username: process.env.DB_USERNAME || 'postgres', password: process.env.DB_PASSWORD || 'postgres', @@ -16,7 +19,10 @@ export const dataSource = new DataSource({ migrations: [path.join(__dirname, './migrations/*{.ts,.js}')], synchronize: false, logging: process.env.DB_LOGGING === 'true', - ssl: { - rejectUnauthorized: false, - }, + // Automatically disable SSL for localhost, enable for remote databases + ssl: isLocalDatabase + ? false + : { + rejectUnauthorized: false, + }, }); From e9c110afd4c6a1023a939049b61a3eea2a0396f9 Mon Sep 17 00:00:00 2001 From: Shannon Clarke Date: Wed, 24 Dec 2025 16:07:47 -0400 Subject: [PATCH 4/4] feat: modify form schema to accept array of objects for beneficiaries --- schemas/primary-school-textbook-grant.json | 529 +++++++++------------ 1 file changed, 212 insertions(+), 317 deletions(-) diff --git a/schemas/primary-school-textbook-grant.json b/schemas/primary-school-textbook-grant.json index 360a20e..e5619bf 100644 --- a/schemas/primary-school-textbook-grant.json +++ b/schemas/primary-school-textbook-grant.json @@ -1,320 +1,215 @@ { - "id": "primary-school-textbook-grant", - "name": "Primary School Textbook Grant Application", - "description": "Apply for a textbook grant for primary school students", - "fields": [ - { - "name": "beneficiaries", - "type": "object", - "label": "Student Information", - "required": true, - "fields": [ - { - "name": "firstName", - "type": "string", - "label": "Student First Name", - "required": true, - "validations": { - "min": 2, - "max": 50 - } - }, - { - "name": "lastName", - "type": "string", - "label": "Student Last Name", - "required": true, - "validations": { - "min": 2, - "max": 50 - } - }, - { - "name": "idNumber", - "type": "string", - "label": "National Identification (ID) Number", - "required": false, - "validations": { - "min": 2, - "message": "ID Number must be at least 2 characters" - } - }, - { - "name": "passportNumber", - "type": "string", - "label": "Passport Number", - "required": false, - "validations": { - "message": "Passport number is required" - } - }, - { - "name": "class", - "type": "string", - "label": "What class are they currently in?", - "required": true, - "validations": { - "regex": "^[1-6]$", - "message": "Class must be between 1 and 6" - } - }, - { - "name": "relationshipToChild", - "type": "string", - "label": "Relationship to Child", - "required": true, - "validations": { - "min": 2, - "message": "Relationship to Child must be at least 2 characters" - } - } - ] - }, - { - "name": "guardian", - "type": "object", - "label": "Guardian Information", - "required": true, - "fields": [ - { - "name": "firstName", - "type": "string", - "label": "Guardian First Name", - "required": true, - "validations": { - "min": 2, - "max": 50 - } - }, - { - "name": "lastName", - "type": "string", - "label": "Guardian Last Name", - "required": true, - "validations": { - "min": 2, - "max": 50 - } - }, - { - "name": "idNumber", - "type": "string", - "label": "Guardian ID Number", - "required": true, - "validations": { - "min": 2, - "max": 50 - } - }, - { - "name": "passportNumber", - "type": "string", - "label": "Passport Number", - "required": false, - "validations": { - "message": "Passport number must be at least 6 characters" - } - }, - { - "name": "tamisNumber", - "type": "string", - "label": "TAMIS Number", - "required": false, - "validations": { - "message": "Tamis must be 10-15 digits" - } - } - ] - }, - { - "name": "applicant", - "type": "object", - "required": true, - "fields": [ - { - "name": "firstName", - "type": "string", - "label": "First name", - "required": true, - "validations": { - "min": 1, - "max": 100, - "message": "First name is required" - } - }, - { - "name": "lastName", - "type": "string", - "label": "Last name", - "required": true, - "validations": { - "min": 1, - "max": 100, - "message": "Last name is required" - } - }, - { - "name": "addressLine1", - "type": "string", - "label": "Address Line 1", - "required": true, - "validations": { - "min": 5, - "max": 200, - "message": "Address must be at least 5 characters" - } - }, - { - "name": "addressLine2", - "type": "string", - "label": "Address Line 2", - "required": false, - "validations": { - "max": 200 - } - }, - { - "name": "parish", - "type": "string", - "label": "Parish", - "required": true, - "validations": { - "regex": "^(christ-church|st-andrew|st-george|st-james|st-john|st-joseph|st-lucy|st-michael|st-peter|st-philip|st-thomas)$", - "message": "Must select a valid parish" - } - }, - { - "name": "postalCode", - "type": "string", - "label": "Postal Code", - "required": false, - "validations": { - "regex": "^BB\\d{5}$", - "message": "Enter a valid postal code (e.g., BB17004)" - } - }, - { - "name": "email", - "type": "email", - "label": "Email Address", - "required": true - }, - { - "name": "telephoneNumber", - "type": "string", - "label": "Telephone Number", - "required": true, - "validations": { - "regex": "^\\+?[0-9]{10,15}$", - "message": "Telephone number must be 10-15 digits" - } - }, - { - "name": "idNumber", - "type": "string", - "label": "National Identification (ID) Number", - "required": false, - "validations": { - "min": 2, - "message": "ID Number must be at least 2 characters" - } - }, - { - "name": "passportNumber", - "type": "string", - "label": "Passport Number", - "required": false, - "validations": { - "message": "Passport number must be at least 6 characters" - } - }, - { - "name": "tamisNumber", - "type": "string", - "label": "TAMIS Number", - "required": false, - "validations": { - "message": "Tamis must be 10-15 digits" - } - } - ] - }, + "id": "primary-school-textbook-grant", + "name": "Primary School Textbook Grant Application", + "description": "Apply for a textbook grant for primary school students", + "fields": [ + { + "name": "beneficiaries", + "type": "array", + "label": "Student Information", + "required": true, + "items": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "guardian": { + "type": "object" + } + } + } + }, - { - "name": "bankAccount", - "type": "object", - "label": "Bank Account Information", - "required": true, - "fields": [ - { - "name": "accountHolderName", - "type": "string", - "label": "Account Holder Name", - "required": true - }, - { - "name": "bankName", - "type": "string", - "label": "Bank Name", - "required": true - }, - { - "name": "accountNumber", - "type": "string", - "label": "Account Number", - "required": true, - "validations": { - "regex": "^[0-9]{6,20}$", - "message": "Account number must be 6-20 digits" - } - }, - { - "name": "branchName", - "type": "string", - "label": "Branch Name", - "required": true, - "validations": { - "max": 100 - } - }, - { - "name": "branchCode", - "type": "string", - "label": "Branch Coe", - "required": true, - "validations": { - "max": 100 - } - }, - { - "name": "accountType", - "type": "string", - "label": "Account Type", - "required": true, - "validations": { - "regex": "^(savings|chequing)$", - "message": "Must select an option" - } - } - ] - } - ], - "processors": [ - { - "type": "email", - "config": { - "to": "{{db:primary-school-textbook-grant:admin_email}}", - "subject": "New Textbook Grant Application - {{formData.beneficiaries.firstName}} {{formData.beneficiaries.lastName}}", - "template": "primary-school-textbook-grant" - } - }, - { - "type": "email", - "config": { - "to": "{{formData.guardian.email}}", - "subject": "Textbook Grant Application Received - Government of Barbados", - "template": "primary-school-textbook-grant-receipt" - } - } - ] + { + "name": "applicant", + "type": "object", + "required": true, + "fields": [ + { + "name": "firstName", + "type": "string", + "label": "First name", + "required": true, + "validations": { + "min": 1, + "max": 100, + "message": "First name is required" + } + }, + { + "name": "lastName", + "type": "string", + "label": "Last name", + "required": true, + "validations": { + "min": 1, + "max": 100, + "message": "Last name is required" + } + }, + { + "name": "addressLine1", + "type": "string", + "label": "Address Line 1", + "required": true, + "validations": { + "min": 5, + "max": 200, + "message": "Address must be at least 5 characters" + } + }, + { + "name": "addressLine2", + "type": "string", + "label": "Address Line 2", + "required": false, + "validations": { + "max": 200 + } + }, + { + "name": "parish", + "type": "string", + "label": "Parish", + "required": true, + "validations": { + "regex": "^(christ-church|st-andrew|st-george|st-james|st-john|st-joseph|st-lucy|st-michael|st-peter|st-philip|st-thomas)$", + "message": "Must select a valid parish" + } + }, + { + "name": "postalCode", + "type": "string", + "label": "Postal Code", + "required": false, + "validations": { + "regex": "^BB\\d{5}$", + "message": "Enter a valid postal code (e.g., BB17004)" + } + }, + { + "name": "email", + "type": "email", + "label": "Email Address", + "required": true + }, + { + "name": "telephoneNumber", + "type": "string", + "label": "Telephone Number", + "required": true, + "validations": { + "regex": "^\\+?[0-9]{10,15}$", + "message": "Telephone number must be 10-15 digits" + } + }, + { + "name": "idNumber", + "type": "string", + "label": "National Identification (ID) Number", + "required": false, + "validations": { + "min": 2, + "message": "ID Number must be at least 2 characters" + } + }, + { + "name": "passportNumber", + "type": "string", + "label": "Passport Number", + "required": false, + "validations": { + "message": "Passport number must be at least 6 characters" + } + }, + { + "name": "tamisNumber", + "type": "string", + "label": "TAMIS Number", + "required": false, + "validations": { + "message": "Tamis must be 10-15 digits" + } + } + ] + }, + + { + "name": "bankAccount", + "type": "object", + "label": "Bank Account Information", + "required": true, + "fields": [ + { + "name": "accountHolderName", + "type": "string", + "label": "Account Holder Name", + "required": true + }, + { + "name": "bankName", + "type": "string", + "label": "Bank Name", + "required": true + }, + { + "name": "accountNumber", + "type": "string", + "label": "Account Number", + "required": true, + "validations": { + "regex": "^[0-9]{6,20}$", + "message": "Account number must be 6-20 digits" + } + }, + { + "name": "branchName", + "type": "string", + "label": "Branch Name", + "required": true, + "validations": { + "max": 100 + } + }, + { + "name": "branchCode", + "type": "string", + "label": "Branch Coe", + "required": true, + "validations": { + "max": 100 + } + }, + { + "name": "accountType", + "type": "string", + "label": "Account Type", + "required": true, + "validations": { + "regex": "^(savings|chequing)$", + "message": "Must select an option" + } + } + ] + } + ], + "processors": [ + { + "type": "email", + "config": { + "to": "{{db:primary-school-textbook-grant:admin_email}}", + "subject": "New Textbook Grant Application - {{formData.beneficiaries.firstName}} {{formData.beneficiaries.lastName}}", + "template": "primary-school-textbook-grant" + } + }, + { + "type": "email", + "config": { + "to": "{{formData.guardian.email}}", + "subject": "Textbook Grant Application Received - Government of Barbados", + "template": "primary-school-textbook-grant-receipt" + } + } + ] }