From e13330fdf3c06449c611d94b7fe8f0775b4b5c77 Mon Sep 17 00:00:00 2001 From: Joe Karow <58997957+JoeKarow@users.noreply.github.com> Date: Wed, 10 Apr 2024 17:25:52 -0400 Subject: [PATCH] fix: attribute saving (#1210) # Pull Request type Please check the type of change your PR introduces: - [x] Bugfix - [ ] Feature - [ ] Code style update (formatting, renaming) - [ ] Refactoring (no functional changes, no API changes) - [ ] Build-related changes - [ ] Documentation content changes - [ ] Other (please describe): ## What is the current behavior? Issue Number: IN-955 ## What is the new behavior? - - - ## Does this introduce a breaking change? - [ ] Yes - [ ] No ## Other information --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- apps/app/next.config.mjs | 2 +- packages/db/client/extensions/auditContext.ts | 8 +- packages/db/client/extensions/idGenerator.ts | 41 ++++++ packages/db/client/extensions/json.ts | 133 +++++++++--------- packages/db/client/index.ts | 46 +++--- packages/db/lib/generateData.ts | 33 ++++- packages/db/lib/generators/allAttributes.ts | 8 +- .../db/lib/generators/attributeCategory.ts | 8 +- .../generators/attributeSuppDataSchemas.ts | 8 +- .../db/lib/generators/attributesByCategory.ts | 8 +- packages/db/lib/generators/langs.ts | 8 +- packages/db/lib/generators/namespaces.ts | 9 +- packages/db/lib/generators/permission.ts | 8 +- packages/db/lib/generators/serviceCategory.ts | 8 +- packages/db/lib/generators/userRole.ts | 8 +- packages/db/lib/generators/userType.ts | 8 +- packages/db/lib/idGen.ts | 3 +- .../data-portal/ServiceEditDrawer/index.tsx | 51 ++++--- .../ui/components/sections/ServicesInfo.tsx | 17 ++- packages/ui/components/sections/VisitCard.tsx | 7 +- packages/ui/hooks/useGoogleMapMarker.tsx | 10 +- packages/ui/modals/Service/processor.tsx | 2 + .../modals/dataPortal/Attributes/fields.tsx | 21 +-- .../ui/modals/dataPortal/Attributes/index.tsx | 20 ++- 24 files changed, 275 insertions(+), 200 deletions(-) create mode 100644 packages/db/client/extensions/idGenerator.ts diff --git a/apps/app/next.config.mjs b/apps/app/next.config.mjs index 3d621882c0..84b9fe34d6 100644 --- a/apps/app/next.config.mjs +++ b/apps/app/next.config.mjs @@ -76,7 +76,7 @@ const nextConfig = { tunnelRoute: '/monitoring', // Hides source maps from generated client bundles - hideSourceMaps: true, + hideSourceMaps: !isLocalDev, // Automatically tree-shake Sentry logger statements to reduce bundle size disableLogger: isVercelProd || isVercelActiveDev, diff --git a/packages/db/client/extensions/auditContext.ts b/packages/db/client/extensions/auditContext.ts index 0b434c0c7f..b76edbaad1 100644 --- a/packages/db/client/extensions/auditContext.ts +++ b/packages/db/client/extensions/auditContext.ts @@ -2,16 +2,16 @@ import { Prisma, prisma } from '~db/client' import { isIdFor } from '~db/lib/idGen' function auditedExtension(actorId: string) { - return Prisma.defineExtension((prisma) => - prisma.$extends({ + return Prisma.defineExtension((client) => + client.$extends({ query: { $allModels: { async $allOperations({ args, query }) { if (!isIdFor('user', actorId)) { throw new Error('Invalid userId') } - const [, result] = await prisma.$transaction([ - prisma.$executeRaw`SELECT set_config('app.actor_id', ${actorId}, TRUE)`, + const [, result] = await client.$transaction([ + client.$executeRaw`SELECT set_config('app.actor_id', ${actorId}, TRUE)`, query(args), ]) return result diff --git a/packages/db/client/extensions/idGenerator.ts b/packages/db/client/extensions/idGenerator.ts new file mode 100644 index 0000000000..eb9a5afa8b --- /dev/null +++ b/packages/db/client/extensions/idGenerator.ts @@ -0,0 +1,41 @@ +import { Prisma } from '~db/client' +import { generateId, idPrefix } from '~db/lib/idGen' + +const applicableModels = Object.keys(idPrefix) as (keyof typeof idPrefix)[] + +const isApplicableModel = (model: string | undefined): model is keyof typeof idPrefix => + Boolean(model) && applicableModels.includes(model as keyof typeof idPrefix) + +export const idGeneratorExtension = Prisma.defineExtension({ + name: 'Id Generator', + query: { + $allOperations({ args, model, operation, query }) { + if (model) { + model = model.charAt(0).toLowerCase() + model.slice(1) + } + if (isApplicableModel(model)) { + switch (operation) { + case 'create': { + if (args.data) { + args.data.id ??= generateId(model) + } + break + } + case 'createMany': { + if (Array.isArray(args.data)) { + args.data.forEach((item: Record) => { + item.id ??= generateId(model) + }) + } + break + } + case 'upsert': { + args.create.id ??= generateId(model) + break + } + } + } + return query(args) + }, + }, +}) diff --git a/packages/db/client/extensions/json.ts b/packages/db/client/extensions/json.ts index b463b6a90f..4a7a158cb7 100644 --- a/packages/db/client/extensions/json.ts +++ b/packages/db/client/extensions/json.ts @@ -5,79 +5,78 @@ const deserialize = (data: unknown) => (isSuperJSONResult(data) ? superjson.dese const processData = (data: T) => (data ? superjson.stringify(data) : data) -export const jsonExtension = Prisma.defineExtension((prisma) => { - return prisma.$extends({ - result: { - attributeSupplement: { - data: { - needs: { data: true }, - compute({ data }) { - return deserialize(data) - }, +export const jsonExtension = Prisma.defineExtension({ + name: 'SuperJSON Serializer', + result: { + attributeSupplement: { + data: { + needs: { data: true }, + compute({ data }) { + return deserialize(data) }, }, - suggestion: { - data: { - needs: { data: true }, - compute({ data }) { - return deserialize(data) - }, + }, + suggestion: { + data: { + needs: { data: true }, + compute({ data }) { + return deserialize(data) }, }, }, - query: { - attributeSupplement: { - create({ args, query }) { - args.data.data = processData(args.data.data) - return query(args) - }, - createMany({ args, query }) { - args.data = Array.isArray(args.data) ? args.data : [args.data] - for (const item of args.data) { - item.data = processData(item.data) - } - return query(args) - }, - update({ args, query }) { - args.data.data = processData(args.data.data) - return query(args) - }, - updateMany({ args, query }) { - args.data.data = processData(args.data.data) - return query(args) - }, - upsert({ args, query }) { - args.create.data = processData(args.create.data) - args.update.data = processData(args.update.data) - return query(args) - }, + }, + query: { + attributeSupplement: { + create({ args, query }) { + args.data.data = processData(args.data.data) + return query(args) }, - suggestion: { - create({ args, query }) { - args.data.data = processData(args.data.data) - return query(args) - }, - createMany({ args, query }) { - args.data = Array.isArray(args.data) ? args.data : [args.data] - for (const item of args.data) { - item.data = processData(item.data) - } - return query(args) - }, - update({ args, query }) { - args.data.data = processData(args.data.data) - return query(args) - }, - updateMany({ args, query }) { - args.data.data = processData(args.data.data) - return query(args) - }, - upsert({ args, query }) { - args.create.data = processData(args.create.data) - args.update.data = processData(args.update.data) - return query(args) - }, + createMany({ args, query }) { + args.data = Array.isArray(args.data) ? args.data : [args.data] + for (const item of args.data) { + item.data = processData(item.data) + } + return query(args) + }, + update({ args, query }) { + args.data.data = processData(args.data.data) + return query(args) + }, + updateMany({ args, query }) { + args.data.data = processData(args.data.data) + return query(args) + }, + upsert({ args, query }) { + args.create.data = processData(args.create.data) + args.update.data = processData(args.update.data) + return query(args) + }, + }, + suggestion: { + create({ args, query }) { + args.data.data = processData(args.data.data) + return query(args) + }, + createMany({ args, query }) { + args.data = Array.isArray(args.data) ? args.data : [args.data] + for (const item of args.data) { + item.data = processData(item.data) + } + return query(args) + }, + update({ args, query }) { + args.data.data = processData(args.data.data) + return query(args) + }, + updateMany({ args, query }) { + args.data.data = processData(args.data.data) + return query(args) + }, + upsert({ args, query }) { + args.create.data = processData(args.create.data) + args.update.data = processData(args.update.data) + return query(args) }, }, - }) + }, }) diff --git a/packages/db/client/index.ts b/packages/db/client/index.ts index 2b295e2e11..780e20a7e9 100644 --- a/packages/db/client/index.ts +++ b/packages/db/client/index.ts @@ -3,8 +3,8 @@ import { type Prisma, PrismaClient } from '@prisma/client' import { createPrismaQueryEventHandler } from 'prisma-query-log' import { createLoggerInstance } from '@weareinreach/util/logger' -import { idMiddleware } from '~db/lib/idMiddleware' -import { superjsonMiddleware } from '~db/lib/superjsonMiddleware' +import { idGeneratorExtension } from '~db/client/extensions/idGenerator' +import { jsonExtension } from '~db/client/extensions/json' const log = createLoggerInstance('prisma') const verboseLogging = Boolean( @@ -12,8 +12,7 @@ const verboseLogging = Boolean( ) declare global { - // allow global `var` declarations - // eslint-disable-next-line no-var + // eslint-disable-next-line no-var -- allow global `var` declarations var prisma: PrismaClient | undefined } @@ -31,31 +30,32 @@ const clientOptions = { errorFormat: 'pretty', } satisfies Prisma.PrismaClientOptions -const prisma = global.prisma || new PrismaClient(clientOptions) +const generateClient = () => { + const client = new PrismaClient(clientOptions) -prisma.$use(idMiddleware) -prisma.$use(superjsonMiddleware) - -const queryLogger = createPrismaQueryEventHandler({ - queryDuration: true, - format: true, - indent: '\t', - // linesBetweenQueries: 2, - language: 'pl/sql', - logger: (data) => log.info(`\n${data}`), -}) - -if (!global.prisma) { if (verboseLogging) { - prisma.$on('query', queryLogger) + const queryLogger = createPrismaQueryEventHandler({ + queryDuration: true, + format: true, + indent: '\t', + language: 'pl/sql', + logger: (data) => log.info(`\n${data}`), + }) + client.$on('query', queryLogger) } else { - prisma.$on('error', (event) => log.error(event)) - prisma.$on('warn', (event) => log.warn(event)) + client.$on('error', (event) => log.error(event)) + client.$on('warn', (event) => log.warn(event)) } + + return client.$extends(jsonExtension).$extends(idGeneratorExtension) as unknown as PrismaClient< + typeof clientOptions + > } -// prisma.$connect() + +const prisma = global.prisma ?? generateClient() + if (process.env.NODE_ENV !== 'production') { - global.prisma = prisma + global.prisma ??= prisma } export { prisma } export type * from '@prisma/client' diff --git a/packages/db/lib/generateData.ts b/packages/db/lib/generateData.ts index 486a147497..e10ef4aadd 100644 --- a/packages/db/lib/generateData.ts +++ b/packages/db/lib/generateData.ts @@ -1,4 +1,5 @@ /* eslint-disable node/no-process-env */ +import { PrismaClient } from '@prisma/client' import { Listr, type ListrDefaultRenderer, @@ -7,19 +8,41 @@ import { type ListrTaskWrapper, PRESET_TIMER, } from 'listr2' +import prettier from 'prettier' -import { prisma } from '~db/client' +import { writeFileSync } from 'fs' +import path from 'path' import * as job from './generators' +/** + * It takes a filename and some data, and writes it to a file in the `generated` directory + * + * @param {string} filename - The base name of the file to write to, **without extension**. + * @param {string} data - The data to be written to the file. + */ +export const writeOutput = async (filename: string, data: string, isJs = false) => { + const prettierOpts = (await prettier.resolveConfig(__dirname)) ?? undefined + const parser = isJs ? 'babel' : 'typescript' + const outFile = `${path.resolve(__dirname, '../generated')}/${filename}.${isJs ? 'mjs' : 'ts'}` + + const formattedOutput = await prettier.format(data, { ...prettierOpts, parser }) + writeFileSync(outFile, formattedOutput) +} + +const prisma = new PrismaClient() + const rendererOptions = { bottomBar: 10, timer: PRESET_TIMER, } -const defineJob = (title: string, job: (task: ListrTask) => void | Promise): ListrJob => ({ +const defineJob = ( + title: string, + jobItem: (ctx: Context, task: ListrTask) => void | Promise +): ListrJob => ({ title, - task: async (_ctx, task): Promise => job(task), rendererOptions, + task: jobItem, skip: !process.env.DATABASE_URL, }) @@ -41,7 +64,7 @@ const tasks = new Listr( defineJob('Translation Namespaces', job.generateNamespaces), defineJob('Attribute Supplement Data Schemas', job.generateDataSchemas), ], - { concurrent: true } + { concurrent: true, ctx: { prisma, writeOutput } } ), }, { @@ -68,6 +91,8 @@ tasks.run() export type Context = { error?: boolean + prisma: typeof prisma + writeOutput: typeof writeOutput } export type ListrTask = ListrTaskWrapper type ListrJob = ListrTaskObj diff --git a/packages/db/lib/generators/allAttributes.ts b/packages/db/lib/generators/allAttributes.ts index c8a3d30264..30d049407b 100644 --- a/packages/db/lib/generators/allAttributes.ts +++ b/packages/db/lib/generators/allAttributes.ts @@ -1,9 +1,7 @@ -import { prisma } from '~db/client' -import { type ListrTask } from '~db/lib/generateData' +import { type Context, type ListrTask } from '~db/lib/generateData' -import { writeOutput } from './common' - -export const generateAllAttributes = async (task: ListrTask) => { +export const generateAllAttributes = async (ctx: Context, task: ListrTask) => { + const { prisma, writeOutput } = ctx const data = await prisma.attribute.findMany({ select: { id: true, diff --git a/packages/db/lib/generators/attributeCategory.ts b/packages/db/lib/generators/attributeCategory.ts index f60d0bbdf4..431a5ed77f 100644 --- a/packages/db/lib/generators/attributeCategory.ts +++ b/packages/db/lib/generators/attributeCategory.ts @@ -1,9 +1,7 @@ -import { prisma } from '~db/client' -import { type ListrTask } from '~db/lib/generateData' +import { type Context, type ListrTask } from '~db/lib/generateData' -import { writeOutput } from './common' - -export const generateAttributeCategories = async (task: ListrTask) => { +export const generateAttributeCategories = async (ctx: Context, task: ListrTask) => { + const { prisma, writeOutput } = ctx const data = await prisma.attributeCategory.findMany({ where: { active: true }, select: { diff --git a/packages/db/lib/generators/attributeSuppDataSchemas.ts b/packages/db/lib/generators/attributeSuppDataSchemas.ts index 7d557a76c0..f11667897d 100644 --- a/packages/db/lib/generators/attributeSuppDataSchemas.ts +++ b/packages/db/lib/generators/attributeSuppDataSchemas.ts @@ -1,11 +1,9 @@ import { type JsonSchemaObject, jsonSchemaToZod } from 'json-schema-to-zod' -import { prisma } from '~db/client' -import { type ListrTask } from '~db/lib/generateData' +import { type Context, type ListrTask } from '~db/lib/generateData' -import { writeOutput } from './common' - -export const generateDataSchemas = async (task: ListrTask) => { +export const generateDataSchemas = async (ctx: Context, task: ListrTask) => { + const { prisma, writeOutput } = ctx const data = await prisma.attributeSupplementDataSchema.findMany({ where: { active: true, diff --git a/packages/db/lib/generators/attributesByCategory.ts b/packages/db/lib/generators/attributesByCategory.ts index bd40d12f21..e6c2c58e91 100644 --- a/packages/db/lib/generators/attributesByCategory.ts +++ b/packages/db/lib/generators/attributesByCategory.ts @@ -1,9 +1,7 @@ -import { prisma } from '~db/client' -import { type ListrTask } from '~db/lib/generateData' +import { type Context, type ListrTask } from '~db/lib/generateData' -import { writeOutput } from './common' - -export const generateAttributesByCategory = async (task: ListrTask) => { +export const generateAttributesByCategory = async (ctx: Context, task: ListrTask) => { + const { prisma, writeOutput } = ctx const data = await prisma.attributeCategory.findMany({ where: { active: true }, select: { diff --git a/packages/db/lib/generators/langs.ts b/packages/db/lib/generators/langs.ts index 0c8b045241..3383cf4e4e 100644 --- a/packages/db/lib/generators/langs.ts +++ b/packages/db/lib/generators/langs.ts @@ -1,7 +1,4 @@ -import { prisma } from '~db/client' -import { type ListrTask } from '~db/lib/generateData' - -import { writeOutput } from './common' +import { type Context, type ListrTask } from '~db/lib/generateData' /** * List of locales to move to the top of the language lists - will affect locale switcher & language selection @@ -10,7 +7,8 @@ import { writeOutput } from './common' // const langsToTop = ['en', 'es', 'fr', 'ar', 'ru', 'zh'] // TODO: [IN-791] Clean up language list - remove duplicates & narrow down to primary langs only -export const generateLanguageFiles = async (task: ListrTask) => { +export const generateLanguageFiles = async (ctx: Context, task: ListrTask) => { + const { prisma, writeOutput } = ctx const languages = await prisma.language.findMany({ select: { nativeName: true, diff --git a/packages/db/lib/generators/namespaces.ts b/packages/db/lib/generators/namespaces.ts index 2b5cff24e5..b77798cab8 100644 --- a/packages/db/lib/generators/namespaces.ts +++ b/packages/db/lib/generators/namespaces.ts @@ -1,12 +1,9 @@ -import { prisma } from '~db/client' -import { type ListrTask } from '~db/lib/generateData' +import { type Context, type ListrTask } from '~db/lib/generateData' -import { writeOutput } from './common' - -// eslint-disable-next-line @typescript-eslint/no-non-null-assertion const camelize = (s: string) => s.replace(/-./g, (x) => x[1]!.toUpperCase()) -export const generateNamespaces = async (task: ListrTask) => { +export const generateNamespaces = async (ctx: Context, task: ListrTask) => { + const { prisma, writeOutput } = ctx const data = await prisma.translationNamespace.findMany({ select: { name: true, diff --git a/packages/db/lib/generators/permission.ts b/packages/db/lib/generators/permission.ts index 6bcc1c24c8..a44f52168e 100644 --- a/packages/db/lib/generators/permission.ts +++ b/packages/db/lib/generators/permission.ts @@ -1,9 +1,7 @@ -import { prisma } from '~db/client' -import { type ListrTask } from '~db/lib/generateData' +import { type Context, type ListrTask } from '~db/lib/generateData' -import { writeOutput } from './common' - -export const generatePermissions = async (task: ListrTask) => { +export const generatePermissions = async (ctx: Context, task: ListrTask) => { + const { prisma, writeOutput } = ctx const permissions = await prisma.permission.findMany({ select: { name: true, diff --git a/packages/db/lib/generators/serviceCategory.ts b/packages/db/lib/generators/serviceCategory.ts index f7ff15e3fc..2abc2bc07b 100644 --- a/packages/db/lib/generators/serviceCategory.ts +++ b/packages/db/lib/generators/serviceCategory.ts @@ -1,9 +1,7 @@ -import { prisma } from '~db/client' -import { type ListrTask } from '~db/lib/generateData' +import { type Context, type ListrTask } from '~db/lib/generateData' -import { writeOutput } from './common' - -export const generateServiceCategories = async (task: ListrTask) => { +export const generateServiceCategories = async (ctx: Context, task: ListrTask) => { + const { prisma, writeOutput } = ctx const data = await prisma.serviceCategory.findMany({ where: { active: true, diff --git a/packages/db/lib/generators/userRole.ts b/packages/db/lib/generators/userRole.ts index fa1cf1fa08..4240f7c622 100644 --- a/packages/db/lib/generators/userRole.ts +++ b/packages/db/lib/generators/userRole.ts @@ -1,9 +1,7 @@ -import { prisma } from '~db/client' -import { type ListrTask } from '~db/lib/generateData' +import { type Context, type ListrTask } from '~db/lib/generateData' -import { writeOutput } from './common' - -export const generateUserRoles = async (task: ListrTask) => { +export const generateUserRoles = async (ctx: Context, task: ListrTask) => { + const { prisma, writeOutput } = ctx const roles = await prisma.userRole.findMany({ select: { id: true, diff --git a/packages/db/lib/generators/userType.ts b/packages/db/lib/generators/userType.ts index c3a47809c6..17c9a7669d 100644 --- a/packages/db/lib/generators/userType.ts +++ b/packages/db/lib/generators/userType.ts @@ -1,9 +1,7 @@ -import { prisma } from '~db/client' -import { type ListrTask } from '~db/lib/generateData' +import { type Context, type ListrTask } from '~db/lib/generateData' -import { writeOutput } from './common' - -export const generateUserTypes = async (task: ListrTask) => { +export const generateUserTypes = async (ctx: Context, task: ListrTask) => { + const { prisma, writeOutput } = ctx const userTypes = await prisma.userType.findMany({ select: { id: true, diff --git a/packages/db/lib/idGen.ts b/packages/db/lib/idGen.ts index 0bc575b217..4b7ab136a1 100644 --- a/packages/db/lib/idGen.ts +++ b/packages/db/lib/idGen.ts @@ -91,8 +91,7 @@ export const isIdFor = (table: Uncapitalize, id: string) => { * @returns A table-prefixed ID */ export const generateId = (table: IdPrefix, seedTime?: Date | number) => { - const seedNum = - typeof seedTime === 'undefined' ? undefined : typeof seedTime === 'number' ? seedTime : seedTime.valueOf() + const seedNum = seedTime instanceof Date ? seedTime.valueOf() : seedTime const prefix = idPrefix[table] const id = Ulid.generate({ time: seedNum }).toCanonical() diff --git a/packages/ui/components/data-portal/ServiceEditDrawer/index.tsx b/packages/ui/components/data-portal/ServiceEditDrawer/index.tsx index 3c8c0f214e..494fce1c86 100644 --- a/packages/ui/components/data-portal/ServiceEditDrawer/index.tsx +++ b/packages/ui/components/data-portal/ServiceEditDrawer/index.tsx @@ -14,7 +14,7 @@ import { } from '@mantine/core' import { useDisclosure } from '@mantine/hooks' import { useTranslation } from 'next-i18next' -import { forwardRef, type ReactNode } from 'react' +import { forwardRef, type ReactNode, useCallback } from 'react' import { useForm } from 'react-hook-form' import { Textarea, TextInput } from 'react-hook-form-mantine' import invariant from 'tiny-invariant' @@ -50,14 +50,17 @@ const ServiceAreaItem = ({ const removeServiceArea = api.serviceArea.delFromArea.useMutation({ onSuccess: () => apiUtils.service.forServiceEditDrawer.invalidate(serviceId), }) + + const actionHandler = useCallback(() => { + if (serviceAreaId) { + removeServiceArea.mutate({ serviceAreaId, countryId, govDistId }) + } + }, [countryId, govDistId, removeServiceArea, serviceAreaId]) + if (!serviceAreaId || !(countryId || govDistId)) { return children } - const actionHandler = () => { - removeServiceArea.mutate({ serviceAreaId, countryId, govDistId }) - } - return ( @@ -114,7 +117,9 @@ const _ServiceEditDrawer = forwardRef const countryTranslation = new Intl.DisplayNames(i18n.language, { type: 'region' }) const serviceAreaObj: Record = {} const { countries, districts } = form.watch('serviceAreas') ?? {} - if (!geoMap) return null + if (!geoMap) { + return null + } const countryIdRegex = /^ctry_.*/ const distIdRegex = /^gdst_.*/ @@ -123,7 +128,9 @@ const _ServiceEditDrawer = forwardRef const array = serviceAreaObj[countryId] invariant(array) const cca2 = countryMap?.byId.get(countryId) - if (!cca2) return + if (!cca2) { + return + } const serviceAreaId = data?.serviceAreas?.id const item = ( @@ -137,7 +144,9 @@ const _ServiceEditDrawer = forwardRef const processDistrict = (govDistId: string) => { const govDist = geoMap.get(govDistId) const country = govDist?.parent?.parent?.id ?? govDist?.parent?.id ?? '' - if (!countryIdRegex.test(country) || !govDist) return + if (!countryIdRegex.test(country) || !govDist) { + return + } serviceAreaObj[country] ??= [] const array = serviceAreaObj[country] invariant(array) @@ -171,7 +180,9 @@ const _ServiceEditDrawer = forwardRef } return Object.entries(serviceAreaObj)?.map(([key, value]) => { const country = countryMap?.byId.get(key) - if (!country) return null + if (!country) { + return null + } return ( {countryTranslation.of(country)} @@ -184,8 +195,13 @@ const _ServiceEditDrawer = forwardRef } // #endregion - - if (!data) return null + const coverageModalSuccessHandler = useCallback(() => { + apiUtils.service.forServiceEditDrawer.invalidate(serviceId) + apiUtils.service.forServiceModal.invalidate(serviceId) + }, [apiUtils.service.forServiceEditDrawer, apiUtils.service.forServiceModal, serviceId]) + if (!data) { + return null + } const { getHelp, publicTransit } = data ? processAccessInstructions({ @@ -249,9 +265,11 @@ const _ServiceEditDrawer = forwardRef Services - {activeServices.map((serviceId) => { - const service = allServices?.find((s) => s.id === serviceId) - if (!service) return null + {activeServices.map((activeServiceId) => { + const service = allServices?.find((s) => s.id === activeServiceId) + if (!service) { + return null + } return ( {t(service.tsKey, { ns: service.tsNs })} @@ -268,10 +286,7 @@ const _ServiceEditDrawer = forwardRef {serviceAreas()} { - apiUtils.service.forServiceEditDrawer.invalidate(serviceId) - apiUtils.service.forServiceModal.invalidate(serviceId) - }} + onSuccessAction={coverageModalSuccessHandler} component={Button} variant={variants.Button.secondarySm} > diff --git a/packages/ui/components/sections/ServicesInfo.tsx b/packages/ui/components/sections/ServicesInfo.tsx index 8df0044cf2..7eeb4b0fd2 100644 --- a/packages/ui/components/sections/ServicesInfo.tsx +++ b/packages/ui/components/sections/ServicesInfo.tsx @@ -1,6 +1,7 @@ import { Card, createStyles, Group, rem, Skeleton, Stack, Text } from '@mantine/core' import { useRouter } from 'next/router' import { useTranslation } from 'next-i18next' +import { useCallback } from 'react' import { transformer } from '@weareinreach/util/transformer' import { Link } from '~ui/components/core' @@ -45,6 +46,12 @@ const ServiceSection = ({ category, services, hideRemoteBadges }: ServiceSection const variants = useCustomVariant() const apiUtils = api.useUtils() + + const preloadService = useCallback( + (serviceId: string) => () => apiUtils.service.forServiceModal.prefetch(serviceId), + [apiUtils.service.forServiceModal] + ) + return ( {Array.isArray(category) ? ( @@ -92,7 +99,7 @@ const ServiceSection = ({ category, services, hideRemoteBadges }: ServiceSection position='apart' noWrap className={classes.group} - onMouseOver={() => apiUtils.service.forServiceModal.prefetch(service.id)} + onMouseOver={preloadService(service.id)} > {children} @@ -132,7 +139,9 @@ export const ServicesInfoCard = ({ parentId, hideRemoteBadges, remoteOnly }: Ser if (serviceMap.has(key)) { const serviceSet = serviceMap.get(key) - if (!serviceSet) continue + if (!serviceSet) { + continue + } serviceSet.add( transformer.stringify({ id: service.id, @@ -165,12 +174,12 @@ export const ServicesInfoCard = ({ parentId, hideRemoteBadges, remoteOnly }: Ser const sections = sectionArray.map(([key, value]) => { const valSet = [...value] - const services = valSet.map((item) => transformer.parse(item)) + const serviceList = valSet.map((item) => transformer.parse(item)) return ( ) diff --git a/packages/ui/components/sections/VisitCard.tsx b/packages/ui/components/sections/VisitCard.tsx index 51a6ced656..ceb2fe4d99 100644 --- a/packages/ui/components/sections/VisitCard.tsx +++ b/packages/ui/components/sections/VisitCard.tsx @@ -135,12 +135,9 @@ const VisitCardEdit = ({ locationId }: VisitCardProps) => { const { data } = api.location.forVisitCardEdits.useQuery(locationId) const formattedAddress = useFormattedAddress(data) - useEffect(() => { if (map && mapIsReady) { - const lat = data?.latitude - const lng = data?.longitude - const name = data?.name + const { name, latitude: lat, longitude: lng } = data ?? {} try { invariant(lat) invariant(lng) @@ -164,7 +161,7 @@ const VisitCardEdit = ({ locationId }: VisitCardProps) => { } } return () => void 0 - }, [data?.name, data?.latitude, data?.longitude, formattedAddress, map, mapIsReady, locationId, mapMarker]) + }, [data, formattedAddress, map, mapIsReady, locationId, mapMarker]) // const isAccessible = location.attributes.some( // (attribute) => attribute.attribute.tsKey === 'additional.wheelchair-accessible' diff --git a/packages/ui/hooks/useGoogleMapMarker.tsx b/packages/ui/hooks/useGoogleMapMarker.tsx index 144bc7137e..bd323ef2c2 100644 --- a/packages/ui/hooks/useGoogleMapMarker.tsx +++ b/packages/ui/hooks/useGoogleMapMarker.tsx @@ -1,5 +1,4 @@ import { MantineProvider, Stack, Text, Title } from '@mantine/core' -import { useWhyDidYouUpdate } from 'ahooks' import { useRouter } from 'next/router' import { type Route } from 'nextjs-routes' import { useCallback, useMemo } from 'react' @@ -49,7 +48,7 @@ export const useGoogleMapMarker = () => { if (!mapIsReady) { throw new Error('map is not ready') } - console.trace('adding new marker', { id, lat, lng, name, address, slug, locationId }) + const position = new google.maps.LatLng({ lat, lng }) const newMarker = marker.get(id) ?? new google.maps.marker.AdvancedMarkerElement() @@ -109,13 +108,6 @@ export const useGoogleMapMarker = () => { () => ({ get: getMarker, add: addMarker, remove: removeMarker }), [addMarker, getMarker, removeMarker] ) - useWhyDidYouUpdate('useGoogleMapMarker', { - router, - infoWindow, - map, - mapIsReady, - clickHandler: markerInfoBoxLinkClickHandler, - }) return markerFns } diff --git a/packages/ui/modals/Service/processor.tsx b/packages/ui/modals/Service/processor.tsx index c140ccbcd7..55ef14ce65 100644 --- a/packages/ui/modals/Service/processor.tsx +++ b/packages/ui/modals/Service/processor.tsx @@ -147,6 +147,7 @@ export const processAttributes = ({ break } /** Target Population & Eligibility Requirements */ + case 'tpop': case 'eligibility': { const type = tsKey.split('.').pop() as string switch (type) { @@ -161,6 +162,7 @@ export const processAttributes = ({ ) break } + case 'other': case 'other-describe': { const { text } = attribute if (!text) break diff --git a/packages/ui/modals/dataPortal/Attributes/fields.tsx b/packages/ui/modals/dataPortal/Attributes/fields.tsx index 80dcd092ce..36b2394148 100644 --- a/packages/ui/modals/dataPortal/Attributes/fields.tsx +++ b/packages/ui/modals/dataPortal/Attributes/fields.tsx @@ -36,8 +36,8 @@ const SuppText = () => { const SuppData = ({ schema }: SuppDataProps) => { const { control } = useFormContext() - const renderField = (schema: FieldAttributes) => { - const { type, name: dataKey, ...schemaProps } = schema + const renderField = (formSchema: FieldAttributes) => { + const { type, name: dataKey, ...schemaProps } = formSchema const baseProps = { ...schemaProps, name: `data.${dataKey}` as const, @@ -48,7 +48,7 @@ const SuppData = ({ schema }: SuppDataProps) => { return } case FieldType.select: { - const { options } = schema + const { options } = formSchema return