From 4c2a486fcb20ab5a043e02b60da5a1eccbef73a8 Mon Sep 17 00:00:00 2001 From: John Darragh Date: Tue, 3 Nov 2020 13:51:16 -0800 Subject: [PATCH] Implement Food Type Checkboxes --- .eslintrc.js | 8 + app/services/stakeholder-best-service.js | 22 +- app/services/stakeholder-log-service.js | 11 +- app/services/stakeholder-service.js | 293 ++++--- client/package-lock.json | 2 +- .../Verification/OrganizationEdit.js | 320 +++++--- .../Verification/VerificationAdminGrid.js | 6 + ...5716_implement-food-type-checkboxes-678.js | 760 ++++++++++++++++++ 8 files changed, 1201 insertions(+), 221 deletions(-) create mode 100644 migrations/1604419645716_implement-food-type-checkboxes-678.js diff --git a/.eslintrc.js b/.eslintrc.js index b679b6fa9..84311232b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -16,4 +16,12 @@ module.exports = { rules: { "prettier/prettier": "error", }, + settings: { + react: { + // Version checking of react. Default is "detect", which + // fails at the root directory, since react is not installed + // here. Providing a dummy number supresses the warning + version: "16.0", + }, + }, }; diff --git a/app/services/stakeholder-best-service.js b/app/services/stakeholder-best-service.js index d56fc8ada..5e7c22675 100644 --- a/app/services/stakeholder-best-service.js +++ b/app/services/stakeholder-best-service.js @@ -62,9 +62,11 @@ const search = async ({ s.donation_delivery_instructions, s.donation_notes, s.covid_notes, s.category_notes, s.eligibility_notes, s.food_types, s.languages, s.v_name, s.v_categories, s.v_address, s.v_phone, s.v_email, - s.v_hours, s.verification_status_id, s.inactive_temporary, + s.v_hours, s.v_food_types, s.verification_status_id, s.inactive_temporary, array_to_json(s.hours) as hours, s.category_ids, s.neighborhood_id, s.is_verified, + s.food_bakery, s.food_dry_goods, s.food_produce, + s.food_dairy, s.food_prepared, s.food_meat, ${locationClause ? `${locationClause} AS distance,` : ""} ${buildLoginSelectsClause()} from stakeholder_set as s @@ -173,6 +175,12 @@ const search = async ({ covidNotes: row.covid_notes || "", categoryNotes: row.category_notes || "", eligibilityNotes: row.eligibility_notes || "", + foodBakery: row.food_bakery, + foodDryGoods: row.food_dry_goods, + foodProduce: row.food_produce, + foodDairy: row.food_dairy, + foodPrepared: row.food_prepared, + foodMeat: row.food_meat, foodTypes: row.food_types || "", languages: row.languages || "", confirmedName: row.v_name, @@ -181,6 +189,7 @@ const search = async ({ confirmedPhone: row.v_phone, confirmedEmail: row.v_email, confirmedHours: row.v_hours, + confirmedFoodTypes: row.v_food_types, verificationStatusId: row.verification_status_id, inactiveTemporary: row.inactive_temporary, neighborhoodId: row.neighborhood_id, @@ -224,8 +233,10 @@ const selectById = async (id) => { s.donation_delivery_instructions, s.donation_notes, s.covid_notes, s.category_notes, s.eligibility_notes, s.food_types, s.languages, s.v_name, s.v_categories, s.v_address, s.v_phone, s.v_email, - s.v_hours, s.verification_status_id, s.inactive_temporary, + s.v_hours, s.v_food_types, s.verification_status_id, s.inactive_temporary, s.neighborhood_id, s.is_verified, + s.food_bakery, s.food_dry_goods, s.food_produce, + s.food_dairy, s.food_prepared, s.food_meat, ${buildLoginSelectsClause()} from stakeholder_best s ${buildLoginJoinsClause()} @@ -296,6 +307,12 @@ const selectById = async (id) => { covidNotes: row.covid_notes || "", categoryNotes: row.category_notes || "", eligibilityNotes: row.eligibility_notes || "", + foodBakery: row.food_bakery, + foodDryGoods: row.food_dry_goods, + foodProduce: row.food_produce, + foodDairy: row.food_dairy, + foodPrepared: row.food_prepared, + foodMeat: row.food_meat, foodTypes: row.food_types || "", languages: row.languages || "", confirmedName: row.v_name, @@ -304,6 +321,7 @@ const selectById = async (id) => { confirmedPhone: row.v_phone, confirmedEmail: row.v_email, confirmedHours: row.v_hours, + confirmedFoodTypes: row.v_food_types, verificationStatusId: row.verification_status_id, inactiveTemporary: row.inactive_temporary, neighborhoodId: row.neighborhood_id, diff --git a/app/services/stakeholder-log-service.js b/app/services/stakeholder-log-service.js index dfa9d7bcc..308b7151c 100644 --- a/app/services/stakeholder-log-service.js +++ b/app/services/stakeholder-log-service.js @@ -31,8 +31,10 @@ const selectById = async (id) => { s.donation_delivery_instructions, s.donation_notes, s.covid_notes, s.category_notes, s.eligibility_notes, s.food_types, s.languages, s.v_name, s.v_categories, s.v_address, s.v_phone, s.v_email, - s.v_hours, s.verification_status_id, s.inactive_temporary, + s.v_hours, s.v_food_types, s.verification_status_id, s.inactive_temporary, s.neighborhood_id, + s.food_bakery, s.food_dry_goods, s.food_produce, + s.food_dairy, s.food_prepared, s.food_meat, ${buildLoginSelectsClause()} from stakeholder_log s ${buildLoginJoinsClause()} @@ -107,11 +109,18 @@ const selectById = async (id) => { confirmedPhone: row.v_phone, confirmedEmail: row.v_email, confirmedHours: row.v_hours, + confirmedFoodTypes: row.v_food_types, verificationStatusId: row.verification_status_id, inactiveTemporary: row.inactive_temporary, neighborhoodId: row.neighborhood_id, neighborhoodName: row.neighborhood_name, completeCriticalPercent: row.complete_critical_percent, + foodBakery: row.food_bakery, + foodDryGoods: row.food_dry_goods, + foodProduce: row.food_produce, + foodDairy: row.food_dairy, + foodPrepared: row.food_prepared, + foodMeat: row.food_meat, }); }); diff --git a/app/services/stakeholder-service.js b/app/services/stakeholder-service.js index 694a0d63b..19254c574 100644 --- a/app/services/stakeholder-service.js +++ b/app/services/stakeholder-service.js @@ -86,10 +86,12 @@ const search = async ({ as claimed_date, s.claimed_login_id, s.requirements, s.admin_notes, s.inactive, s.email, s.covid_notes, s.v_name, s.v_categories, s.v_address, s.v_phone, s.v_email, - s.v_hours, s.verification_status_id, s.inactive_temporary, + s.v_hours, s.v_food_types, s.verification_status_id, s.inactive_temporary, s.neighborhood_id, n.name as neighborhood_name, s.complete_critical_percent, ${locationClause ? `${locationClause} AS distance,` : ""} + s.food_bakery, s.food_dry_goods, s.food_produce, + s.food_dairy, s.food_prepared, s.food_meat, ${buildLoginSelectsClause()} from stakeholder_set as s left outer join neighborhood n on s.neighborhood_id = n.id @@ -199,11 +201,18 @@ const search = async ({ confirmedPhone: row.v_phone, confirmedEmail: row.v_email, confirmedHours: row.v_hours, + confirmedFoodTypes: row.v_food_types, verificationStatusId: row.verification_status_id, inactiveTemporary: row.inactive_temporary, neighborhoodId: row.neighborhood_id, neighborhoodName: row.neighborhood_name, completeCriticalPercent: row.complete_critical_percent, + foodBakery: row.food_bakery, + foodDryGoods: row.food_dry_goods, + foodProduce: row.food_produce, + foodDairy: row.food_dairy, + foodPrepared: row.food_prepared, + foodMeat: row.food_meat, }); }); @@ -249,8 +258,10 @@ const selectById = async (id) => { s.donation_delivery_instructions, s.donation_notes, s.covid_notes, s.category_notes, s.eligibility_notes, s.food_types, s.languages, s.v_name, s.v_categories, s.v_address, s.v_phone, s.v_email, - s.v_hours, s.verification_status_id, s.inactive_temporary, + s.v_hours, s.v_food_types, s.verification_status_id, s.inactive_temporary, s.neighborhood_id, + s.food_bakery, s.food_dry_goods, s.food_produce, + s.food_dairy, s.food_prepared, s.food_meat, ${buildLoginSelectsClause()} from stakeholder s ${buildLoginJoinsClause()} @@ -329,9 +340,16 @@ const selectById = async (id) => { confirmedPhone: row.v_phone, confirmedEmail: row.v_email, confirmedHours: row.v_hours, + confirmedFoodTypes: row.v_food_types, verificationStatusId: row.verification_status_id, inactiveTemporary: row.inactive_temporary, neighborhoodId: row.neighborhood_id, + foodBakery: row.food_bakery, + foodDryGoods: row.food_dry_goods, + foodProduce: row.food_produce, + foodDairy: row.food_dairy, + foodPrepared: row.food_prepared, + foodMeat: row.food_meat, }; // Don't have a distance, since we didn't specify origin @@ -541,8 +559,15 @@ const insert = async (model) => { confirmedPhone, confirmedEmail, confirmedHours, + confirmedFoodTypes, verificationStatusId, inactiveTemporary, + foodBakery, + foodDryGoods, + foodProduce, + foodDairy, + foodPrepared, + foodMeat, } = model; try { let hoursSqlValues = hours.length @@ -562,66 +587,71 @@ const insert = async (model) => { // (ARRAY['(2,Wed,13:02,13:04)', '(3,Thu,07:00,08:00)'])::stakeholder_hours[]); --array of stakeholder_hours // objects, which are defined as a postgres type (see repo file for more detail on this type). const invokeSprocSql = `CALL create_stakeholder( - ${toSqlNumeric(0)}::INT, - ${toSqlNumeric(tenantId)}::INT, - ${toSqlString(name)}::VARCHAR, ${toSqlString( - address1 - )}::VARCHAR, ${toSqlString(address2)}::VARCHAR, - ${toSqlString(city)}::VARCHAR, ${toSqlString( - state - )}::VARCHAR, ${toSqlString(zip)}::VARCHAR, - ${toSqlString(phone)}::VARCHAR, - ${toSqlNumeric(latitude)}::NUMERIC, ${toSqlNumeric(longitude)}::NUMERIC, - ${toSqlString(website)}::VARCHAR, ${toSqlBoolean(inactive)}, - ${toSqlString(notes)}::VARCHAR, ${toSqlString(requirements)}::VARCHAR, - ${toSqlString(adminNotes)}::VARCHAR, ${toSqlNumeric(loginId)}::INT, - ${toSqlString(parentOrganization)}::VARCHAR, ${toSqlString( - physicalAccess - )}::VARCHAR, - ${toSqlString(email)}::VARCHAR, ${toSqlString(items)}::VARCHAR, - ${toSqlString(services)}::VARCHAR, ${toSqlString(facebook)}::VARCHAR, - ${toSqlString(twitter)}::VARCHAR, ${toSqlString(pinterest)}::VARCHAR, - ${toSqlString(linkedin)}::VARCHAR, ${toSqlString(description)}::VARCHAR, - ${toSqlTimestamp(submittedDate)}::TIMESTAMPTZ, ${toSqlNumeric( - submittedLoginId - )}::INT, - ${toSqlTimestamp(approvedDate)}::TIMESTAMP, - ${toSqlNumeric(reviewedLoginId)}::INT, - ${toSqlTimestamp(assignedDate)}::TIMESTAMP, ${toSqlNumeric( - assignedLoginId - )}::INT, - ${toSqlTimestamp(claimedDate)}::TIMESTAMP, ${toSqlNumeric( - claimedLoginId - )}::INT, - ${toSqlString(reviewNotes)}::VARCHAR, ${toSqlString(instagram)}::VARCHAR, - ${toSqlString(adminContactName)}::VARCHAR, ${toSqlString( - adminContactPhone - )}::VARCHAR, - ${toSqlString(adminContactEmail)}::VARCHAR, - ${toSqlString(donationContactName)}::VARCHAR, - ${toSqlString(donationContactPhone)}::VARCHAR, - ${toSqlString(donationContactEmail)}::VARCHAR, - ${toSqlBoolean(donationPickup)}, - ${toSqlBoolean(donationAcceptFrozen)}, - ${toSqlBoolean(donationAcceptRefrigerated)}, - ${toSqlBoolean(donationAcceptPerishable)}, - ${toSqlString(donationSchedule)}::VARCHAR, - ${toSqlString(donationDeliveryInstructions)}::VARCHAR, - ${toSqlString(donationNotes)}::VARCHAR, - ${toSqlString(covidNotes)}::VARCHAR, - ${toSqlString(categoryNotes)}::VARCHAR, - ${toSqlString(eligibilityNotes)}::VARCHAR, - ${toSqlString(foodTypes)}::VARCHAR, - ${toSqlString(languages)}::VARCHAR, - ${toSqlBoolean(confirmedName)}, - ${toSqlBoolean(confirmedCategories)}, - ${toSqlBoolean(confirmedAddress)}, - ${toSqlBoolean(confirmedPhone)}, - ${toSqlBoolean(confirmedEmail)}, - ${toSqlBoolean(confirmedHours)}, - ${toSqlNumeric(verificationStatusId)}::INT, - ${toSqlBoolean(inactiveTemporary)}, - ${categories}, ${formattedHours})`; + ${toSqlNumeric(0)}::INT, + ${toSqlNumeric(tenantId)}::INT, + ${toSqlString(name)}::VARCHAR, + ${toSqlString(address1)}::VARCHAR, + ${toSqlString(address2)}::VARCHAR, + ${toSqlString(city)}::VARCHAR, + ${toSqlString(state)}::VARCHAR, + ${toSqlString(zip)}::VARCHAR, + ${toSqlString(phone)}::VARCHAR, + ${toSqlNumeric(latitude)}::NUMERIC, + ${toSqlNumeric(longitude)}::NUMERIC, + ${toSqlString(website)}::VARCHAR, ${toSqlBoolean(inactive)}, + ${toSqlString(notes)}::VARCHAR, + ${toSqlString(requirements)}::VARCHAR, + ${toSqlString(adminNotes)}::VARCHAR, + ${toSqlNumeric(loginId)}::INT, + ${toSqlString(parentOrganization)}::VARCHAR, + ${toSqlString(physicalAccess)}::VARCHAR, + ${toSqlString(email)}::VARCHAR, + ${toSqlString(items)}::VARCHAR, + ${toSqlString(services)}::VARCHAR, ${toSqlString(facebook)}::VARCHAR, + ${toSqlString(twitter)}::VARCHAR, ${toSqlString(pinterest)}::VARCHAR, + ${toSqlString(linkedin)}::VARCHAR, ${toSqlString(description)}::VARCHAR, + ${toSqlTimestamp(submittedDate)}::TIMESTAMPTZ, + ${toSqlNumeric(submittedLoginId)}::INT, + ${toSqlTimestamp(approvedDate)}::TIMESTAMP, + ${toSqlNumeric(reviewedLoginId)}::INT, + ${toSqlTimestamp(assignedDate)}::TIMESTAMP, + ${toSqlNumeric(assignedLoginId)}::INT, + ${toSqlTimestamp(claimedDate)}::TIMESTAMP, + ${toSqlNumeric(claimedLoginId)}::INT, + ${toSqlString(reviewNotes)}::VARCHAR, + ${toSqlString(instagram)}::VARCHAR, + ${toSqlString(adminContactName)}::VARCHAR, + ${toSqlString(adminContactPhone)}::VARCHAR, + ${toSqlString(adminContactEmail)}::VARCHAR, + ${toSqlString(donationContactName)}::VARCHAR, + ${toSqlString(donationContactPhone)}::VARCHAR, + ${toSqlString(donationContactEmail)}::VARCHAR, + ${toSqlBoolean(donationPickup)}, + ${toSqlBoolean(donationAcceptFrozen)}, + ${toSqlBoolean(donationAcceptRefrigerated)}, + ${toSqlBoolean(donationAcceptPerishable)}, + ${toSqlString(donationSchedule)}::VARCHAR, + ${toSqlString(donationDeliveryInstructions)}::VARCHAR, + ${toSqlString(donationNotes)}::VARCHAR, + ${toSqlString(covidNotes)}::VARCHAR, + ${toSqlString(categoryNotes)}::VARCHAR, + ${toSqlString(eligibilityNotes)}::VARCHAR, + ${toSqlString(foodTypes)}::VARCHAR, + ${toSqlString(languages)}::VARCHAR, + ${toSqlBoolean(confirmedName)}, + ${toSqlBoolean(confirmedCategories)}, + ${toSqlBoolean(confirmedAddress)}, + ${toSqlBoolean(confirmedPhone)}, + ${toSqlBoolean(confirmedEmail)}, + ${toSqlBoolean(confirmedHours)}, + ${toSqlBoolean(confirmedFoodTypes)}, + ${toSqlNumeric(verificationStatusId)}::INT, + ${toSqlBoolean(inactiveTemporary)}, + ${categories}, ${formattedHours}, + ${toSqlBoolean(foodBakery)}, ${toSqlBoolean(foodDryGoods)}, + ${toSqlBoolean(foodProduce)}, ${toSqlBoolean(foodDairy)}, + ${toSqlBoolean(foodPrepared)}, ${toSqlBoolean(foodMeat)} + )`; const stakeholderResult = await pool.query(invokeSprocSql); const id = stakeholderResult.rows[0].s_id; return { id }; @@ -787,8 +817,15 @@ const update = async (model) => { confirmedPhone, confirmedEmail, confirmedHours, + confirmedFoodTypes, verificationStatusId, inactiveTemporary, + foodBakery, + foodDryGoods, + foodProduce, + foodDairy, + foodPrepared, + foodMeat, } = model; let hoursSqlValues = hours.length @@ -812,70 +849,74 @@ const update = async (model) => { // (ARRAY['(2,Wed,13:02,13:04)', '(3,Thu,07:00,08:00)'])::stakeholder_hours[]); --array of stakeholder_hours // objects, which are defined as a postgres type (see repo file for more detail on this type). const invokeSprocSql = `CALL update_stakeholder ( - ${toSqlString(name)}::VARCHAR, ${toSqlString( - address1 - )}::VARCHAR, ${toSqlString(address2)}::VARCHAR, - ${toSqlString(city)}::VARCHAR, ${toSqlString( - state - )}::VARCHAR, ${toSqlString(zip)}::VARCHAR, ${toSqlString(phone)}::VARCHAR, - ${toSqlNumeric(latitude)}::NUMERIC, ${toSqlNumeric( - longitude - )}::NUMERIC, ${toSqlString(website)}::VARCHAR, - ${toSqlBoolean(inactive)}, ${toSqlString(notes)}::VARCHAR, ${toSqlString( - requirements - )}::VARCHAR, - ${toSqlString(adminNotes)}::VARCHAR, ${toSqlString( - parentOrganization - )}::VARCHAR, ${toSqlString(physicalAccess)}::VARCHAR, - ${toSqlString(email)}::VARCHAR, ${toSqlString( - items - )}::VARCHAR, ${toSqlString(services)}::VARCHAR, ${toSqlString( - facebook - )}::VARCHAR, - ${toSqlString(twitter)}::VARCHAR, ${toSqlString( - pinterest - )}::VARCHAR, ${toSqlString(linkedin)}::VARCHAR, ${toSqlString( - description - )}::VARCHAR, - ${toSqlNumeric(loginId)}::INT, ${toSqlTimestamp( - submittedDate - )}::TIMESTAMPTZ, ${toSqlNumeric(submittedLoginId)}::INT, - ${toSqlTimestamp(approvedDate)}::TIMESTAMP, - ${toSqlNumeric(reviewedLoginId)}::INT, - ${toSqlTimestamp(assignedDate)}::TIMESTAMP, ${toSqlNumeric( - assignedLoginId - )}::INT, ${toSqlTimestamp(claimedDate)}::TIMESTAMP, - ${toSqlNumeric(claimedLoginId)}::INT, ${toSqlString( - reviewNotes - )}::VARCHAR, ${toSqlString(instagram)}::VARCHAR, - ${toSqlString(adminContactName)}::VARCHAR, ${toSqlString( - adminContactPhone - )}::VARCHAR, ${toSqlString(adminContactEmail)}::VARCHAR, - ${toSqlString(donationContactName)}::VARCHAR, ${toSqlString( - donationContactPhone - )}::VARCHAR, ${toSqlString(donationContactEmail)}::VARCHAR, - ${toSqlBoolean(donationPickup)}, ${toSqlBoolean( - donationAcceptFrozen - )}, ${toSqlBoolean(donationAcceptRefrigerated)}, - ${toSqlBoolean(donationAcceptPerishable)}, ${toSqlString( - donationSchedule - )}::VARCHAR, ${toSqlString(donationDeliveryInstructions)}::VARCHAR, - ${toSqlString(donationNotes)}::VARCHAR, ${toSqlString( - covidNotes - )}::VARCHAR, ${toSqlString(categoryNotes)}::VARCHAR, - ${toSqlString(eligibilityNotes)}::VARCHAR, ${toSqlString( - foodTypes - )}::VARCHAR, ${toSqlString(languages)}::VARCHAR, - ${toSqlBoolean(confirmedName)}, ${toSqlBoolean( - confirmedCategories - )}, ${toSqlBoolean(confirmedAddress)}, - ${toSqlBoolean(confirmedPhone)}, ${toSqlBoolean( - confirmedEmail - )}, ${toSqlBoolean(confirmedHours)}, - ${toSqlNumeric(verificationStatusId)}::INT, ${toSqlBoolean( - inactiveTemporary - )}, - ${id}, ${categories}, ${formattedHours})`; + ${toSqlString(name)}::VARCHAR, + ${toSqlString(address1)}::VARCHAR, + ${toSqlString(address2)}::VARCHAR, + ${toSqlString(city)}::VARCHAR, + ${toSqlString(state)}::VARCHAR, + ${toSqlString(zip)}::VARCHAR, + ${toSqlString(phone)}::VARCHAR, + ${toSqlNumeric(latitude)}::NUMERIC, + ${toSqlNumeric(longitude)}::NUMERIC, + ${toSqlString(website)}::VARCHAR, + ${toSqlBoolean(inactive)}, + ${toSqlString(notes)}::VARCHAR, + ${toSqlString(requirements)}::VARCHAR, + ${toSqlString(adminNotes)}::VARCHAR, + ${toSqlString(parentOrganization)}::VARCHAR, + ${toSqlString(physicalAccess)}::VARCHAR, + ${toSqlString(email)}::VARCHAR, + ${toSqlString(items)}::VARCHAR, + ${toSqlString(services)}::VARCHAR, + ${toSqlString(facebook)}::VARCHAR, + ${toSqlString(twitter)}::VARCHAR, + ${toSqlString(pinterest)}::VARCHAR, + ${toSqlString(linkedin)}::VARCHAR, + ${toSqlString(description)}::VARCHAR, + ${toSqlNumeric(loginId)}::INT, + ${toSqlTimestamp(submittedDate)}::TIMESTAMPTZ, + ${toSqlNumeric(submittedLoginId)}::INT, + ${toSqlTimestamp(approvedDate)}::TIMESTAMP, + ${toSqlNumeric(reviewedLoginId)}::INT, + ${toSqlTimestamp(assignedDate)}::TIMESTAMP, + ${toSqlNumeric(assignedLoginId)}::INT, + ${toSqlTimestamp(claimedDate)}::TIMESTAMP, + ${toSqlNumeric(claimedLoginId)}::INT, + ${toSqlString(reviewNotes)}::VARCHAR, + ${toSqlString(instagram)}::VARCHAR, + ${toSqlString(adminContactName)}::VARCHAR, + ${toSqlString(adminContactPhone)}::VARCHAR, + ${toSqlString(adminContactEmail)}::VARCHAR, + ${toSqlString(donationContactName)}::VARCHAR, + ${toSqlString(donationContactPhone)}::VARCHAR, + ${toSqlString(donationContactEmail)}::VARCHAR, + ${toSqlBoolean(donationPickup)}, + ${toSqlBoolean(donationAcceptFrozen)}, + ${toSqlBoolean(donationAcceptRefrigerated)}, + ${toSqlBoolean(donationAcceptPerishable)}, + ${toSqlString(donationSchedule)}::VARCHAR, + ${toSqlString(donationDeliveryInstructions)}::VARCHAR, + ${toSqlString(donationNotes)}::VARCHAR, + ${toSqlString(covidNotes)}::VARCHAR, + ${toSqlString(categoryNotes)}::VARCHAR, + ${toSqlString(eligibilityNotes)}::VARCHAR, + ${toSqlString(foodTypes)}::VARCHAR, + ${toSqlString(languages)}::VARCHAR, + ${toSqlBoolean(confirmedName)}, + ${toSqlBoolean(confirmedCategories)}, + ${toSqlBoolean(confirmedAddress)}, + ${toSqlBoolean(confirmedPhone)}, + ${toSqlBoolean(confirmedEmail)}, ${toSqlBoolean(confirmedHours)}, + ${toSqlBoolean(confirmedFoodTypes)}, + ${toSqlNumeric(verificationStatusId)}::INT, + ${toSqlBoolean(inactiveTemporary)}, + ${id}, + ${categories}, + ${formattedHours}, + ${toSqlBoolean(foodBakery)}, ${toSqlBoolean(foodDryGoods)}, + ${toSqlBoolean(foodProduce)}, ${toSqlBoolean(foodDairy)}, + ${toSqlBoolean(foodPrepared)}, ${toSqlBoolean(foodMeat)} + )`; try { await pool.query(invokeSprocSql); diff --git a/client/package-lock.json b/client/package-lock.json index e1fadc0a2..9a7412c48 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,6 +1,6 @@ { "name": "food-oasis-client", - "version": "1.0.26", + "version": "1.0.28", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/client/src/components/Verification/OrganizationEdit.js b/client/src/components/Verification/OrganizationEdit.js index d255fbe59..5ad1786f9 100644 --- a/client/src/components/Verification/OrganizationEdit.js +++ b/client/src/components/Verification/OrganizationEdit.js @@ -190,8 +190,15 @@ const emptyOrganization = { confirmedEmail: false, confirmedPhone: false, confirmedHours: false, + confirmedFoodTypes: false, verificationStatusId: VERIFICATION_STATUS.NEEDS_VERIFICATION, inactiveTemporary: false, + foodBakery: false, + foodDryGoods: false, + foodProduce: false, + foodDairy: false, + foodPrepared: false, + foodMeat: false, }; const OrganizationEdit = (props) => { @@ -1091,113 +1098,244 @@ const OrganizationEdit = (props) => { Details for Food Seekers to See - - + + + Food Types + + + + setFieldValue( + "confirmedFoodTypes", + e.target.checked + ) + } + onBlur={handleBlur} + size="medium" + /> + } + label="Confirm Food Types" + /> + - - + + setFieldValue("foodBakery", !values.foodBakery) + } + onBlur={handleBlur} + /> + } + label="Baked Goods" /> - - + + setFieldValue("foodDryGoods", !values.foodDryGoods) + } + onBlur={handleBlur} + /> + } + label="Dry Goods" /> - - + + setFieldValue("foodProduce", !values.foodProduce) + } + onBlur={handleBlur} + /> } + label="Produce" /> - - + + setFieldValue("foodDairy", !values.foodDairy) + } + onBlur={handleBlur} + /> } + label="Dairy" /> - - + + setFieldValue("foodPrepared", !values.foodPrepared) + } + onBlur={handleBlur} + /> + } + label="Prepared Food" /> - - + + setFieldValue("foodMeat", !values.foodMeat) + } + onBlur={handleBlur} + /> + } + label="Meat" /> + + + + + + + + + + + + + + + + + + + + + diff --git a/client/src/components/Verification/VerificationAdminGrid.js b/client/src/components/Verification/VerificationAdminGrid.js index 7f7f34c04..376a1b890 100644 --- a/client/src/components/Verification/VerificationAdminGrid.js +++ b/client/src/components/Verification/VerificationAdminGrid.js @@ -159,6 +159,12 @@ const adminColumns = [ formatter: confirmationFormatter, width: 60, }, + { + key: "confirmedFoodTypes", + name: "FoodTypes", + formatter: confirmationFormatter, + width: 60, + }, { key: "neighborhoodName", name: "Neighborhood", diff --git a/migrations/1604419645716_implement-food-type-checkboxes-678.js b/migrations/1604419645716_implement-food-type-checkboxes-678.js new file mode 100644 index 000000000..adb33740b --- /dev/null +++ b/migrations/1604419645716_implement-food-type-checkboxes-678.js @@ -0,0 +1,760 @@ +/* eslint-disable camelcase */ + +exports.shorthands = undefined; + +exports.up = (pgm) => { + pgm.sql( + ` + ALTER TABLE stakeholder ADD COLUMN IF NOT EXISTS food_bakery boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder ADD COLUMN IF NOT EXISTS food_dry_goods boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder ADD COLUMN IF NOT EXISTS food_produce boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder ADD COLUMN IF NOT EXISTS food_dairy boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder ADD COLUMN IF NOT EXISTS food_prepared boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder ADD COLUMN IF NOT EXISTS food_meat boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder ADD COLUMN IF NOT EXISTS v_food_types boolean NOT NULL DEFAULT false; + + ALTER TABLE stakeholder_best ADD COLUMN IF NOT EXISTS food_bakery boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder_best ADD COLUMN IF NOT EXISTS food_dry_goods boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder_best ADD COLUMN IF NOT EXISTS food_produce boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder_best ADD COLUMN IF NOT EXISTS food_dairy boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder_best ADD COLUMN IF NOT EXISTS food_prepared boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder_best ADD COLUMN IF NOT EXISTS food_meat boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder_best ADD COLUMN IF NOT EXISTS v_food_types boolean NOT NULL DEFAULT false; + + ALTER TABLE stakeholder_log ADD COLUMN IF NOT EXISTS food_bakery boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder_log ADD COLUMN IF NOT EXISTS food_dry_goods boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder_log ADD COLUMN IF NOT EXISTS food_produce boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder_log ADD COLUMN IF NOT EXISTS food_dairy boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder_log ADD COLUMN IF NOT EXISTS food_prepared boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder_log ADD COLUMN IF NOT EXISTS food_meat boolean NOT NULL DEFAULT false; + ALTER TABLE stakeholder_log ADD COLUMN IF NOT EXISTS v_food_types boolean NOT NULL DEFAULT false; + ` + ); + + pgm.sql( + ` + CREATE OR REPLACE PROCEDURE public.update_stakeholder( + s_name character varying, + s_address_1 character varying, + s_address_2 character varying, + s_city character varying, + s_state character varying, + s_zip character varying, + s_phone character varying, + s_latitude numeric, + s_longitude numeric, + s_website character varying, + s_inactive boolean, + s_notes character varying, + s_requirements character varying, + s_admin_notes character varying, + s_parent_organization character varying, + s_physical_access character varying, + s_email character varying, + s_items character varying, + s_services character varying, + s_facebook character varying, + s_twitter character varying, + s_pinterest character varying, + s_linkedin character varying, + s_description character varying, + s_modified_login_id integer, + s_submitted_date timestamp with time zone, + s_submitted_login_id integer, + s_approved_date timestamp without time zone, + s_reviewed_login_id integer, + s_assigned_date timestamp without time zone, + s_assigned_login_id integer, + s_claimed_date timestamp without time zone, + s_claimed_login_id integer, + s_review_notes character varying, + s_instagram character varying, + s_admin_contact_name character varying, + s_admin_contact_phone character varying, + s_admin_contact_email character varying, + s_donation_contact_name character varying, + s_donation_contact_phone character varying, + s_donation_contact_email character varying, + s_donation_pickup boolean, + s_donation_accept_frozen boolean, + s_donation_accept_refrigerated boolean, + s_donation_accept_perishable boolean, + s_donation_schedule character varying, + s_donation_delivery_instructions character varying, + s_donation_notes character varying, + s_covid_notes character varying, + s_category_notes character varying, + s_eligibility_notes character varying, + s_food_types character varying, + s_languages character varying, + s_v_name boolean, + s_v_categories boolean, + s_v_address boolean, + s_v_phone boolean, + s_v_email boolean, + s_v_hours boolean, + s_v_food_types boolean, + s_verification_status_id integer, + s_inactive_temporary boolean, + s_id integer, + categories integer[], + hours_array stakeholder_hours[], + s_food_bakery boolean, + s_food_dry_goods boolean, + s_food_produce boolean, + s_food_dairy boolean, + s_food_prepared boolean, + s_food_meat boolean) + LANGUAGE 'plpgsql' + + AS $BODY$ + DECLARE cat INT; + DECLARE hours_element stakeholder_hours; + DECLARE critical_percent INT; + + BEGIN + + SELECT CASE WHEN (s_inactive OR s_inactive_temporary) THEN + (s_v_name::integer + s_v_categories::integer + s_v_address::integer) *100/3 + ELSE + (s_v_name::integer + s_v_categories::integer + s_v_address::integer + + s_v_email::integer + s_v_phone::integer + s_v_hours::integer + + s_v_food_types::integer) *100/7 + END INTO critical_percent; + + -- update the stakeholder table itself + UPDATE stakeholder + SET + name = s_name, + address_1 = s_address_1, + address_2 = s_address_2, + city = s_city, + state = s_state, + zip = s_zip, + phone = s_phone, + latitude = s_latitude, + longitude = s_longitude, + website = s_website, + inactive = s_inactive, + notes = s_notes, + requirements = s_requirements, + admin_notes = s_admin_notes, + parent_organization = s_parent_organization, + physical_access = s_physical_access, + email = s_email, + items = s_items, + services = s_services, + facebook = s_facebook, + twitter = s_twitter, + pinterest = s_pinterest, + linkedin = s_linkedin, + description = s_description, + modified_login_id = s_modified_login_id, + modified_date = CURRENT_TIMESTAMP, + submitted_date = s_submitted_date, + submitted_login_id = s_submitted_login_id, + approved_date = s_approved_date, + reviewed_login_id = s_reviewed_login_id, + assigned_date = s_assigned_date, + assigned_login_id = s_assigned_login_id, + claimed_date = s_claimed_date, + claimed_login_id = s_claimed_login_id, + review_notes = s_review_notes, + instagram = s_instagram, + admin_contact_name = s_admin_contact_name, + admin_contact_phone = s_admin_contact_phone, + admin_contact_email = s_admin_contact_email, + donation_contact_name = s_donation_contact_name, + donation_contact_phone = s_donation_contact_phone, + donation_contact_email = s_donation_contact_email, + donation_pickup = s_donation_pickup, + donation_accept_frozen = s_donation_accept_frozen, + donation_accept_refrigerated = s_donation_accept_refrigerated, + donation_accept_perishable = s_donation_accept_perishable, + donation_schedule = s_donation_schedule, + donation_delivery_instructions = s_donation_delivery_instructions, + donation_notes = s_donation_notes, + covid_notes = s_covid_notes, + category_notes = s_category_notes, + eligibility_notes = s_eligibility_notes, + food_types = s_food_types, + languages = s_languages, + v_name = s_v_name, + v_categories = s_v_categories, + v_address = s_v_address, + v_phone = s_v_phone, + v_email = s_v_email, + v_hours = s_v_hours, + v_food_types = s_v_food_types, + verification_status_id = s_verification_status_id, + inactive_temporary = s_inactive_temporary, + hours = hours_array, + category_ids = categories, + complete_critical_percent = critical_percent, + food_bakery = s_food_bakery, + food_dry_goods = s_food_dry_goods, + food_produce = s_food_produce, + food_dairy = s_food_dairy, + food_prepared = s_food_prepared, + food_meat = s_food_meat + WHERE + id=s_id; + + -- delete previous stakeholder category + DELETE FROM stakeholder_category WHERE stakeholder_id=s_id; + -- ...and insert new stakeholder category(s) + FOREACH cat IN ARRAY categories + LOOP + INSERT INTO stakeholder_category + (stakeholder_id, category_id) + VALUES (s_id, cat); + END LOOP; + -- delete previous schedule + DELETE FROM stakeholder_schedule WHERE stakeholder_id=s_id; + -- ...and insert new schedule(s) + FOREACH hours_element IN ARRAY hours_array + LOOP + INSERT INTO stakeholder_schedule( + stakeholder_id, day_of_week, open, close, week_of_month + ) VALUES( + s_id, + hours_element.day_of_week, + hours_element.open::time without time zone, + hours_element.close::time without time zone, + hours_element.week_of_month + ); + END LOOP; + COMMIT; + END; + $BODY$; + ` + ); + + pgm.sql(` + CREATE OR REPLACE PROCEDURE public.create_stakeholder( + INOUT s_id integer, + s_tenant_id integer, + s_name character varying, + s_address_1 character varying, + s_address_2 character varying, + s_city character varying, + s_state character varying, + s_zip character varying, + s_phone character varying, + s_latitude numeric, + s_longitude numeric, + s_website character varying, + s_inactive boolean, + s_notes character varying, + s_requirements character varying, + s_admin_notes character varying, + s_created_login_id integer, + s_parent_organization character varying, + s_physical_access character varying, + s_email character varying, + s_items character varying, + s_services character varying, + s_facebook character varying, + s_twitter character varying, + s_pinterest character varying, + s_linkedin character varying, + s_description character varying, + s_submitted_date timestamp with time zone, + s_submitted_login_id integer, + s_approved_date timestamp without time zone, + s_reviewed_login_id integer, + s_assigned_date timestamp without time zone, + s_assigned_login_id integer, + s_claimed_date timestamp without time zone, + s_claimed_login_id integer, + s_review_notes character varying, + s_instagram character varying, + s_admin_contact_name character varying, + s_admin_contact_phone character varying, + s_admin_contact_email character varying, + s_donation_contact_name character varying, + s_donation_contact_phone character varying, + s_donation_contact_email character varying, + s_donation_pickup boolean, + s_donation_accept_frozen boolean, + s_donation_accept_refrigerated boolean, + s_donation_accept_perishable boolean, + s_donation_schedule character varying, + s_donation_delivery_instructions character varying, + s_donation_notes character varying, + s_covid_notes character varying, + s_category_notes character varying, + s_eligibility_notes character varying, + s_food_types character varying, + s_languages character varying, + s_v_name boolean, + s_v_categories boolean, + s_v_address boolean, + s_v_phone boolean, + s_v_email boolean, + s_v_hours boolean, + s_v_food_types boolean, + s_verification_status_id integer, + s_inactive_temporary boolean, + categories integer[], + hours_array stakeholder_hours[], + s_food_bakery boolean, + s_food_dry_goods boolean, + s_food_produce boolean, + s_food_dairy boolean, + s_food_prepared boolean, + s_food_meat boolean) + LANGUAGE 'plpgsql' + + AS $BODY$ + DECLARE cat INT; + DECLARE hours_element stakeholder_hours; + DECLARE critical_percent INT; + BEGIN + SELECT CASE WHEN (s_inactive OR s_inactive_temporary) THEN + (s_v_name::integer + s_v_categories::integer + s_v_address::integer) *100/3 + ELSE + (s_v_name::integer + s_v_categories::integer + s_v_address::integer + + s_v_email::integer + s_v_phone::integer + s_v_hours::integer) *100/6 + END INTO critical_percent; + + INSERT INTO stakeholder ( + tenant_id, + name, address_1, address_2, city, state, zip, + phone, latitude, longitude, + website, inactive, notes, requirements, admin_notes, created_login_id, + parent_organization, physical_access, email, + items, services, facebook, twitter, pinterest, linkedin, description, + submitted_date, submitted_login_id, approved_date, reviewed_login_id, + assigned_date, assigned_login_id, claimed_date, claimed_login_id, + review_notes, instagram, admin_contact_name, + admin_contact_phone, admin_contact_email, + donation_contact_name, donation_contact_phone, + donation_contact_email, donation_pickup, + donation_accept_frozen, donation_accept_refrigerated, + donation_accept_perishable, donation_schedule, + donation_delivery_instructions, donation_notes, covid_notes, + category_notes, eligibility_notes, food_types, languages, + v_name, v_categories, v_address, + v_phone, v_email, v_hours, v_food_types, + verification_status_id, inactive_temporary, + hours, category_ids, neighborhood_id, complete_critical_percent, + food_bakery, food_dry_goods , food_produce, food_dairy, food_prepared, food_meat) + VALUES ( + s_tenant_id, + s_name, s_address_1, s_address_2, s_city, s_state, s_zip, + s_phone, s_latitude, s_longitude, + s_website, s_inactive, s_notes, s_requirements, s_admin_notes, s_created_login_id, + s_parent_organization, s_physical_access, s_email, + s_items, s_services, s_facebook, s_twitter, s_pinterest, s_linkedin, s_description, + s_submitted_date, s_submitted_login_id, s_approved_date, s_reviewed_login_id, + s_assigned_date, s_assigned_login_id, s_claimed_date, s_claimed_login_id, + s_review_notes, s_instagram, s_admin_contact_name, + s_admin_contact_phone, s_admin_contact_email, + s_donation_contact_name, s_donation_contact_phone, + s_donation_contact_email, s_donation_pickup, + s_donation_accept_frozen, s_donation_accept_refrigerated, + s_donation_accept_perishable, s_donation_schedule, + s_donation_delivery_instructions, s_donation_notes, s_covid_notes, + s_category_notes, s_eligibility_notes, s_food_types, s_languages, + s_v_name, s_v_categories, s_v_address, + s_v_phone, s_v_email, s_v_hours, s_v_food_types, + s_verification_status_id, s_inactive_temporary, + hours_array, categories, + (SELECT id FROM neighborhood WHERE ST_Contains(geometry, ST_Point(s_longitude, s_latitude)) LIMIT 1), + critical_percent, + s_food_bakery, s_food_dry_goods , s_food_produce, s_food_dairy, s_food_prepared, s_food_meat + ) RETURNING id INTO s_id; + + -- insert new stakeholder category(s) + FOREACH cat IN ARRAY categories + LOOP + INSERT INTO stakeholder_category + (stakeholder_id, category_id) + VALUES (s_id, cat); + END LOOP; + + -- insert new schedule(s) + FOREACH hours_element IN ARRAY hours_array + LOOP + INSERT INTO stakeholder_schedule( + stakeholder_id, day_of_week, open, close, week_of_month + ) VALUES( + s_id, + hours_element.day_of_week, + hours_element.open::time without time zone, + hours_element.close::time without time zone, + hours_element.week_of_month + ); + END LOOP; + COMMIT; + END; + $BODY$; + `); + + pgm.sql(` + DROP PROCEDURE IF EXISTS public.update_stakeholder( + varchar,varchar,varchar,varchar,varchar, + varchar,varchar,numeric,numeric,varchar,bool, + varchar,varchar,varchar,varchar,varchar,varchar, + varchar,varchar,varchar,varchar,varchar,varchar, + varchar,int4,timestamptz,int4,timestamp,int4, + timestamp,int4,timestamp,int4,varchar,varchar, + varchar,varchar,varchar,varchar,varchar,varchar, + bool,bool,bool,bool,varchar,varchar,varchar,varchar, + varchar,varchar,varchar,varchar,bool,bool,bool,bool, + bool,bool,int4,bool,int4,_int4,_stakeholder_hours); + + DROP PROCEDURE IF EXISTS public.create_stakeholder( + int4,varchar,varchar,varchar,varchar,varchar,varchar,varchar,numeric,numeric, + varchar,bool,varchar,varchar,varchar,int4,varchar,varchar,varchar,varchar,varchar, + varchar,varchar,varchar,varchar,varchar,timestamptz,int4,timestamp,int4,timestamp, + int4,timestamp,int4,varchar,varchar,varchar,varchar,varchar,varchar,varchar, + varchar,bool,bool,bool,bool,varchar,varchar,varchar,varchar,varchar,varchar, + varchar,varchar,bool,bool,bool,bool,bool,bool,int4,bool,_int4,_stakeholder_hours,int4); + + DROP PROCEDURE IF EXISTS public.create_stakeholder( + varchar,varchar,varchar,varchar,varchar,varchar,varchar,numeric,numeric,varchar, + bool,varchar,varchar,varchar,int4,varchar,varchar,varchar,varchar,varchar, + varchar,varchar,varchar,varchar,varchar,timestamptz,int4,timestamp,int4, + timestamp,int4,timestamp,int4,varchar,varchar,varchar,varchar,varchar, + varchar,varchar,varchar,bool,bool,bool,bool,varchar,varchar,varchar,varchar, + varchar,varchar,varchar,varchar,bool,bool,bool,bool,bool,bool,int4,bool,_int4, + _stakeholder_hours,int4); + + DROP PROCEDURE IF EXISTS public.create_stakeholder( + int4,varchar,varchar,varchar,varchar,varchar,varchar,varchar,numeric,numeric, + varchar,bool,varchar,varchar,varchar,int4,varchar,varchar,varchar,varchar, + varchar,varchar,varchar,varchar,varchar,varchar,timestamptz,int4,timestamp, + int4,timestamp,int4,timestamp,int4,varchar,varchar,varchar,varchar,varchar, + varchar,varchar,varchar,bool,bool,bool,bool,varchar,varchar,varchar,varchar, + varchar,varchar,varchar,varchar,bool,bool,bool,bool,bool,bool,int4,bool,_int4, + _stakeholder_hours); + + DROP PROCEDURE IF EXISTS public.create_stakeholder( + varchar,varchar,varchar,varchar,varchar,varchar,varchar,numeric,numeric, + varchar,bool,varchar,varchar,varchar,int4,varchar,varchar,varchar,varchar, + varchar,varchar,varchar,varchar,varchar,varchar,timestamptz,int4,timestamp, + timestamp,int4,timestamp,int4,timestamp,int4,varchar,varchar,varchar,varchar, + varchar,varchar,varchar,varchar,bool,bool,bool,bool,varchar,varchar,varchar, + varchar,varchar,varchar,varchar,varchar,bool,bool,bool,bool,bool,bool,int4,bool, + _int4,_stakeholder_hours); + + DROP PROCEDURE IF EXISTS public.create_stakeholder( + int4,int4,varchar,varchar,varchar,varchar,varchar,varchar,varchar,numeric, + numeric,varchar,bool,varchar,varchar,varchar,int4,varchar,varchar,varchar, + varchar,varchar,varchar,varchar,varchar,varchar,varchar,timestamptz,int4, + timestamp,int4,timestamp,int4,timestamp,int4,varchar,varchar,varchar,varchar, + varchar,varchar,varchar,varchar,bool,bool,bool,bool,varchar,varchar,varchar, + varchar,varchar,varchar,varchar,varchar,bool,bool,bool,bool,bool,bool,int4,bool, + _int4,_stakeholder_hours); + + DROP PROCEDURE IF EXISTS public.create_stakeholder( + varchar,varchar,varchar,varchar,varchar,varchar,varchar,numeric,numeric, + varchar,bool,varchar,varchar,varchar,int4,varchar,varchar,varchar,varchar, + varchar,varchar,varchar,varchar,varchar,varchar,timestamptz,int4,timestamp, + timestamp,int4,timestamp,int4,timestamp,int4,varchar,varchar,varchar,varchar, + varchar,varchar,varchar,varchar,bool,bool,bool,bool,varchar,varchar,varchar, + varchar,varchar,varchar,varchar,varchar,bool,bool,bool,bool,bool,bool,int4,bool, + _int4,_stakeholder_hours,int4); + + `); + + pgm.sql(` + CREATE OR REPLACE FUNCTION public.on_insert_or_update_stakeholder() + RETURNS trigger + LANGUAGE 'plpgsql' + COST 100 + VOLATILE NOT LEAKPROOF + AS $BODY$ + DECLARE + best_row stakeholder_log%ROWTYPE; + latest_version INTEGER; + is_verified BOOLEAN := false; + categoryid INTEGER; + BEGIN + INSERT INTO public.stakeholder_log + (id, tenant_id, version, name, address_1, address_2, city, state, zip, + phone, latitude, longitude, website, fm_id, notes, + created_date, created_login_id, modified_date, modified_login_id, + requirements, admin_notes, inactive, parent_organization, + physical_access, email, items, services, facebook, twitter, + pinterest, + linkedin, + description, + approved_date, + reviewed_login_id, + assigned_login_id, + agency_type, + assigned_date, + review_notes, + claimed_login_id, + claimed_date, + instagram, + admin_contact_name, + admin_contact_phone, + admin_contact_email, + donation_contact_name, + donation_contact_phone, + donation_contact_email, + donation_pickup, + donation_accept_frozen, + donation_accept_refrigerated, + donation_accept_perishable, + donation_schedule, + donation_delivery_instructions, + covid_notes, + donation_notes, + category_notes, + eligibility_notes, + food_types, + languages, + verification_status_id, + inactive_temporary, + v_name, v_categories, v_address, v_email, v_phone, v_hours, v_food_types, + hours, category_ids, + neighborhood_id, + complete_critical_percent, + food_bakery, food_dry_goods , food_produce, food_dairy, food_prepared, food_meat + ) + VALUES ( + NEW.id, NEW.tenant_id, + (SELECT greatest(max(version) + 1, 1) FROM public.stakeholder_log where id = NEW.id), + NEW.name, + NEW.address_1, + NEW.address_2, + NEW.city, + NEW.state, + NEW.zip, + NEW.phone, + NEW.latitude, + NEW.longitude, + NEW.website, + NEW.fm_id, + NEW.notes, + NEW.created_date, + NEW.created_login_id, + NEW.modified_date, + NEW.modified_login_id, + NEW.requirements, + NEW.admin_notes, + NEW.inactive, + NEW.parent_organization, + NEW.physical_access, + NEW.email, + NEW.items, + NEW.services, + NEW.facebook, + NEW.twitter, + NEW.pinterest, + NEW.linkedin, + NEW.description, + NEW.approved_date, + NEW.reviewed_login_id, + NEW.assigned_login_id, + NEW.agency_type, + NEW.assigned_date, + NEW.review_notes, + NEW.claimed_login_id, + NEW.claimed_date, + NEW.instagram, + NEW.admin_contact_name, + NEW.admin_contact_phone, + NEW.admin_contact_email, + NEW.donation_contact_name, + NEW.donation_contact_phone, + NEW.donation_contact_email, + NEW.donation_pickup, + NEW.donation_accept_frozen, + NEW.donation_accept_refrigerated, + NEW.donation_accept_perishable, + NEW.donation_schedule, + NEW.donation_delivery_instructions, + NEW.covid_notes, + NEW.donation_notes, + NEW.category_notes, + NEW.eligibility_notes, + NEW.food_types, + NEW.languages, + NEW.verification_status_id, + NEW.inactive_temporary, + NEW.v_name, + NEW.v_categories, + NEW.v_address, + NEW.v_email, + NEW.v_phone, + NEW.v_hours, + NEW.v_food_types, + NEW.hours, + NEW.category_ids, + (SELECT id FROM neighborhood WHERE ST_Contains(geometry, ST_Point(NEW.longitude, NEW.latitude)) LIMIT 1), + NEW.complete_critical_percent, + NEW.food_bakery, NEW.food_dry_goods , NEW.food_produce, NEW.food_dairy, NEW.food_prepared, NEW.food_meat + ) RETURNING version INTO latest_version; + + -- We might need to select a new row as our "best" row for this stakeholder. + -- "best" is defined as the highest version in stakeholder_log with verification_status_id=4 + -- (4 means "verified"). + -- Barring that, the highest version is the "best". + + SELECT * INTO best_row FROM stakeholder_log + WHERE id=NEW.id + AND verification_status_id=4 + AND version=(select MAX(version) from stakeholder_log where id=NEW.id AND verification_status_id=4); + + -- Is there anything in best_row? (there might not be, if there are no verified rows) + IF NOT FOUND THEN + -- Fall back on finding the highest version number, which *just so happens* to be this row! + SELECT * INTO best_row FROM stakeholder_log + WHERE id=NEW.id + AND version=latest_version; + ELSE + is_verified = true; + END IF; + + IF FOUND THEN + DELETE FROM stakeholder_best where id=best_row.id; + INSERT INTO stakeholder_best + (id, tenant_id, name, address_1, address_2, city, state, zip, + phone, latitude, longitude, website, fm_id, notes, + created_date, created_login_id, modified_date, modified_login_id, + requirements, admin_notes, inactive, parent_organization, + physical_access, email, items, services, facebook, twitter, + pinterest, + linkedin, + description, + approved_date, + reviewed_login_id, + assigned_login_id, + agency_type, + assigned_date, + review_notes, + claimed_login_id, + claimed_date, + instagram, + admin_contact_name, + admin_contact_phone, + admin_contact_email, + donation_contact_name, + donation_contact_phone, + donation_contact_email, + donation_pickup, + donation_accept_frozen, + donation_accept_refrigerated, + donation_accept_perishable, + donation_schedule, + donation_delivery_instructions, + covid_notes, + donation_notes, + category_notes, + eligibility_notes, + food_types, + languages, + verification_status_id, + inactive_temporary, + v_name, v_categories, v_address, v_email, v_phone, v_hours, v_food_types, + hours, category_ids, + neighborhood_id, + complete_critical_percent, + food_bakery, food_dry_goods , food_produce, food_dairy, food_prepared, food_meat, + is_verified + ) + VALUES ( + best_row.id, + best_row.tenant_id, + best_row.name, + best_row.address_1, + best_row.address_2, + best_row.city, + best_row.state, + best_row.zip, + best_row.phone, + best_row.latitude, + best_row.longitude, + best_row.website, + best_row.fm_id, + best_row.notes, + best_row.created_date, + best_row.created_login_id, + best_row.modified_date, + best_row.modified_login_id, + best_row.requirements, + best_row.admin_notes, + best_row.inactive, + best_row.parent_organization, + best_row.physical_access, + best_row.email, + best_row.items, + best_row.services, + best_row.facebook, + best_row.twitter, + best_row.pinterest, + best_row.linkedin, + best_row.description, + best_row.approved_date, + best_row.reviewed_login_id, + best_row.assigned_login_id, + best_row.agency_type, + best_row.assigned_date, + best_row.review_notes, + best_row.claimed_login_id, + best_row.claimed_date, + best_row.instagram, + best_row.admin_contact_name, + best_row.admin_contact_phone, + best_row.admin_contact_email, + best_row.donation_contact_name, + best_row.donation_contact_phone, + best_row.donation_contact_email, + best_row.donation_pickup, + best_row.donation_accept_frozen, + best_row.donation_accept_refrigerated, + best_row.donation_accept_perishable, + best_row.donation_schedule, + best_row.donation_delivery_instructions, + best_row.covid_notes, + best_row.donation_notes, + best_row.category_notes, + best_row.eligibility_notes, + best_row.food_types, + best_row.languages, + best_row.verification_status_id, + best_row.inactive_temporary, + best_row.v_name, + best_row.v_categories, + best_row.v_address, + best_row.v_email, + best_row.v_phone, + best_row.v_hours, + best_row.v_food_types, + best_row.hours, + best_row.category_ids, + best_row.neighborhood_id, + best_row.complete_critical_percent, + best_row.food_bakery, best_row.food_dry_goods , best_row.food_produce, + best_row.food_dairy, best_row.food_prepared, best_row.food_meat, + is_verified); + + /* Populate normalized stakeholder_best_category table */ + IF best_row.category_ids IS NOT NULL THEN + FOREACH categoryid IN ARRAY best_row.category_ids + LOOP + INSERT INTO stakeholder_best_category + (stakeholder_id, category_id) + VALUES (best_row.id, categoryid); + END LOOP; + END IF; + ELSE + -- should probably log some sort of error, because this should never happen + RAISE EXCEPTION 'Could not find a best version of stakeholder id %', NEW.id; + END IF; + + RETURN NEW; + END; + $BODY$; + `); +}; + +exports.down = () => { + // not reversible +};