Skip to content

Commit

Permalink
fix: misc data portal (#1233)
Browse files Browse the repository at this point in the history
<!--- Please provide a general summary of your changes in the title
above -->

# Pull Request type

<!-- Please try to limit your pull request to one type; submit multiple
pull requests if needed. -->

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):

Issue Number:

- IN-965
- IN-966

## Does this introduce a breaking change?

- [ ] Yes
- [ ] No

<!-- If this does introduce a breaking change, please describe the
impact and migration path for existing applications below. -->

## Summary by CodeRabbit

- **New Features**
- Introduced attribute editing capabilities in the API and UI, allowing
for modifications such as toggling active status and deleting
attributes.
- Enhanced service editing interfaces with new components and logic for
attribute management.
- Added default values in forms for better initial user interaction and
data handling.

- **Refactor**
- Restructured service processing logic for better clarity and
maintainability, including handling of various service-related
attributes.
	- Improved error handling and data structure updates in service modals.

- **Documentation**
- Added and updated type definitions and interfaces for service
processing, enhancing development clarity and supporting new features.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
JoeKarow and kodiakhq[bot] authored Apr 20, 2024
1 parent 3a2f374 commit da82c52
Show file tree
Hide file tree
Showing 34 changed files with 1,694 additions and 707 deletions.
2 changes: 1 addition & 1 deletion InReach.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
},
"prettier.resolveGlobalModules": false,
"typescript.preferences.importModuleSpecifier": "non-relative",
"typescript.tsdk": "✨ InReach (root)/node_modules/typescript/lib",
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"typescript.workspaceSymbols.scope": "allOpenProjects",
"sonarlint.connectedMode.project": {
Expand Down
9 changes: 9 additions & 0 deletions packages/api/router/component/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,13 @@ export const componentRouter = defineRouter({
)
return handler(opts)
}),
AttributeEditWrapper: permissionedProcedure('updateOrgService')
.input(schema.ZAttributeEditWrapperSchema)
.mutation(async (opts) => {
const handler = await importHandler(
namespaced('AttributeEditWrapper'),
() => import('./mutation.AttributeEditWrapper.handler')
)
return handler(opts)
}),
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { getAuditedClient } from '@weareinreach/db'
import { handleError } from '~api/lib/errorHandler'
import { type TRPCHandlerParams } from '~api/types/handler'

import { type TAttributeEditWrapperSchema } from './mutation.AttributeEditWrapper.schema'

export const AttributeEditWrapper = async ({
ctx,
input,
}: TRPCHandlerParams<TAttributeEditWrapperSchema, 'protected'>) => {
try {
const prisma = getAuditedClient(ctx.actorId)

const { id, action } = input
if (action === 'delete') {
const deleteResult = await prisma.attributeSupplement.delete({
where: { id },
})
return deleteResult
}

const current = await prisma.attributeSupplement.findUniqueOrThrow({
where: { id },
select: { active: true },
})
const updateResult = await prisma.attributeSupplement.update({
where: { id },
data: { active: !current.active },
})
return updateResult
} catch (error) {
return handleError(error)
}
}
export default AttributeEditWrapper
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { z } from 'zod'

import { prefixedId } from '~api/schemas/idPrefix'

export const ZAttributeEditWrapperSchema = z.object({
id: prefixedId('attributeSupplement'),
action: z.enum(['toggleActive', 'delete']),
})
export type TAttributeEditWrapperSchema = z.infer<typeof ZAttributeEditWrapperSchema>
1 change: 1 addition & 0 deletions packages/api/router/component/schemas.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// codegen:start {preset: barrel, include: ./*.schema.ts}
export * from './mutation.AttributeEditWrapper.schema'
export * from './mutation.EditModeBarDelete.schema'
export * from './mutation.EditModeBarPublish.schema'
export * from './mutation.EditModeBarReverify.schema'
Expand Down
6 changes: 6 additions & 0 deletions packages/api/router/orgWebsite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,10 @@ export const orgWebsiteRouter = defineRouter({
)
return handler(opts)
}),
upsert: permissionedProcedure('updateOrgWebsite')
.input(schema.ZUpsertSchema)
.mutation(async (opts) => {
const handler = await importHandler(namespaced('upsert'), () => import('./mutation.upsert.handler'))
return handler(opts)
}),
})
78 changes: 78 additions & 0 deletions packages/api/router/orgWebsite/mutation.upsert.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import {
generateId,
generateNestedFreeText,
generateNestedFreeTextUpsert,
getAuditedClient,
Prisma,
} from '@weareinreach/db'
import { handleError } from '~api/lib/errorHandler'
import { connectOne, createOne } from '~api/schemas/nestedOps'
import { type TRPCHandlerParams } from '~api/types/handler'

import { type Create, type TUpsertSchema } from './mutation.upsert.schema'

type CreateData = Pick<Create, 'url' | 'isPrimary' | 'deleted' | 'published' | 'orgLocationOnly'>
export const upsert = async ({ ctx, input }: TRPCHandlerParams<TUpsertSchema, 'protected'>) => {
try {
const prisma = getAuditedClient(ctx.actorId)
const { description: desc, operation, id: passedId, orgLocationId, organizationId, ...data } = input

const isCreateData = (op: 'create' | 'update', inputData: typeof data): inputData is CreateData =>
op === 'create'
const isCreate = operation === 'create'

const id = isCreate ? passedId ?? generateId('orgEmail') : passedId

const generateDescription = ():
| Prisma.FreeTextCreateNestedOneWithoutOrgWebsiteInput
| Prisma.FreeTextUpdateOneWithoutOrgWebsiteNestedInput
| undefined => {
if (!desc || !organizationId) {
return undefined
}
if (isCreateData(operation, data)) {
return Prisma.validator<Prisma.FreeTextCreateNestedOneWithoutOrgWebsiteInput>()(
generateNestedFreeText({
orgId: organizationId,
text: desc,
type: 'websiteDesc',
itemId: id,
})
)
} else {
return Prisma.validator<Prisma.FreeTextUpdateOneWithoutOrgWebsiteNestedInput>()(
generateNestedFreeTextUpsert({
orgId: organizationId,
text: desc,
type: 'websiteDesc',
itemId: id,
})
)
}
}
const description = generateDescription()

const result = isCreateData(operation, data)
? await prisma.orgWebsite.create({
data: {
id,
...(description && { description }),
...data,
locations: createOne(orgLocationId, 'orgLocationId'),
organization: connectOne(organizationId, 'id'),
},
})
: await prisma.orgWebsite.update({
where: { id },
data: {
...(description && { description }),
...data,
},
})

return result
} catch (error) {
return handleError(error)
}
}
export default upsert
34 changes: 34 additions & 0 deletions packages/api/router/orgWebsite/mutation.upsert.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { z } from 'zod'

import { prefixedId } from '~api/schemas/idPrefix'

const base = z
.object({
id: prefixedId('orgWebsite'),
url: z.string().url('Invalid URL. Must start with either "https://" or "http://"'),
description: z.string().nullable(),
isPrimary: z.boolean(),
published: z.boolean(),
deleted: z.boolean(),
organizationId: prefixedId('organization'),
orgLocationId: prefixedId('orgLocation').nullable(),
orgLocationOnly: z.boolean(),
})
.partial()

const create = z
.object({
operation: z.literal('create'),
})
.merge(base.required({ url: true, organizationId: true }))
const update = z
.object({
operation: z.literal('update'),
})
.merge(base.required({ id: true }))

export type Create = z.infer<typeof create>
export type Update = z.infer<typeof update>

export const ZUpsertSchema = z.discriminatedUnion('operation', [create, update])
export type TUpsertSchema = z.infer<typeof ZUpsertSchema>
1 change: 1 addition & 0 deletions packages/api/router/orgWebsite/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
export * from './mutation.create.schema'
export * from './mutation.locationLink.schema'
export * from './mutation.update.schema'
export * from './mutation.upsert.schema'
export * from './query.forContactInfo.schema'
export * from './query.forContactInfoEdit.schema'
export * from './query.forEditDrawer.schema'
Expand Down
77 changes: 58 additions & 19 deletions packages/api/schemas/nestedOps.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/consistent-type-assertions */
import compact from 'just-compact'
import invariant from 'tiny-invariant'

const isString = (x: unknown): x is string => typeof x === 'string'

/**
* `*************`
*
Expand Down Expand Up @@ -33,35 +36,54 @@ export const createManyOptional = <T extends Array<any>>(data: T | undefined) =>
}

/** Individual create record */
export const createOne = <T extends Record<string, any>>(data: T | undefined) =>
!data
? undefined
: ({
create: data,
} as const)
export const connectOne = <T extends Record<string, any>>(data: T | undefined) =>
!data
? undefined
: ({
connect: data,
} as const)
export const createOne = <T extends Record<string, any> | string, K extends string = 'id'>(
data: T | null | undefined,
key?: K
): undefined | { create: T extends string ? { [Key in K]: T } : T } => {
if (!data) {
return undefined
}
if (isString(data)) {
return { create: { [key ?? 'id']: data } as T extends string ? { [Key in K]: T } : T }
}
return {
create: data as T extends string ? { [Key in K]: T } : T,
}
}

export const connectOne = <T extends Record<string, any> | string, K extends string = 'id'>(
data: T | null | undefined,
key?: K
): undefined | { connect: T extends string ? { [Key in K]: T } : T } => {
if (!data) {
return undefined
}
if (isString(data)) {
return { connect: { [key ?? 'id']: data } as T extends string ? { [Key in K]: T } : T }
}
return {
connect: data as T extends string ? { [Key in K]: T } : T,
}
}
export const connectOneId = <T extends string>(id: T | undefined | null) =>
!id ? undefined : ({ connect: { id } } as const)

export const connectOneIdRequired = <T extends string>(id: T) => {
invariant(id)
return { connect: { id } }
}
export const connectOrDisconnectId = <T extends string | null | undefined>(id: T) => {
switch (id) {
case null: {
try {
if (id === null) {
return { disconnect: true }
}
case undefined: {
return
}
default: {
if (typeof id === 'string') return { connect: { id } }
if (id === undefined) {
return undefined
}
invariant(id)
return { connect: { id } }
} catch {
return undefined
}
}

Expand Down Expand Up @@ -107,3 +129,20 @@ export const connectOneRequired = <T extends Record<string, any>>(data: T) => {
connect: data,
}
}

export const connectOrCreateOne = <T extends string, K extends string = 'id'>(
id: T | undefined | null,
key?: K
): { connectOrCreate: { where: { [Key in K]: T }; create: { [Key in K]: T } } } | undefined => {
if (!id) {
return undefined
}
const idObj = { [key ?? 'id']: id } as { [Key in K]: T }

return {
connectOrCreate: {
where: idObj,
create: idObj,
},
}
}
5 changes: 4 additions & 1 deletion packages/db/lib/generateFreeText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ export const generateFreeText = <T extends GenerateFreeTextType>({
invariant(itemId)
return createKey([orgId, itemId, 'description'])
}
default: {
return null
}
}
})()
const ns = namespaces.orgData
Expand Down Expand Up @@ -67,7 +70,7 @@ export const generateNestedFreeText = <T extends GenerateFreeTextType>(args: Gen

export const generateNestedFreeTextUpsert = <T extends GenerateFreeTextType>(
args: GenerateFreeTextParams<T>
): Prisma.FreeTextUpdateOneWithoutOrgEmailNestedInput => {
) => {
const { freeText, translationKey } = generateFreeText(args)
return {
upsert: {
Expand Down
Loading

0 comments on commit da82c52

Please sign in to comment.