Skip to content

Commit

Permalink
fix(IN-958): WebsiteDrawer editing (#1208)
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):

## What is the current behavior?

<!-- Please describe the current behavior that you are modifying, or
link to a relevant issue. -->

Issue Number: IN-958

## What is the new behavior?

<!-- Please describe the behavior or changes that are being added by
this PR. -->

-
-
-

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

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

## Other information

<!-- Any other information that is important to this PR, such as
screenshots of how the component looks before and after the change. -->
  • Loading branch information
JoeKarow authored Apr 9, 2024
1 parent 2904f0c commit 06f1e88
Show file tree
Hide file tree
Showing 15 changed files with 244 additions and 127 deletions.
1 change: 1 addition & 0 deletions packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"libphonenumber-js": "1.10.60",
"luxon": "3.4.4",
"nanoid": "5.0.7",
"remeda": "1.58.0",
"slugify": "1.6.6",
"tiny-invariant": "1.3.3",
"zod": "3.22.4"
Expand Down
31 changes: 27 additions & 4 deletions packages/api/router/orgWebsite/mutation.update.handler.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,38 @@
import * as R from 'remeda'

import { getAuditedClient } from '@weareinreach/db'
import { type TRPCHandlerParams } from '~api/types/handler'

import { type TUpdateSchema } from './mutation.update.schema'

export const update = async ({ ctx, input }: TRPCHandlerParams<TUpdateSchema, 'protected'>) => {
const { where, data } = input
const prisma = getAuditedClient(ctx.actorId)
const updated = await prisma.orgWebsite.update({
const {
where,
data,
})
return updated
data: { url },
} = input
console.log(input)
if (R.isString(url)) {
const { locations, ...rest } = data
const upserted = await prisma.orgWebsite.upsert({
where,
create: {
id: where.id,
url,
...(locations && { locations: { create: locations.upsert.create } }),
...rest,
},
update: data,
})

return upserted
} else {
const updated = await prisma.orgWebsite.update({
where,
data,
})
return updated
}
}
export default update
28 changes: 25 additions & 3 deletions packages/api/router/orgWebsite/mutation.update.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,33 @@ export const ZUpdateSchema = z
isPrimary: z.boolean(),
published: z.boolean(),
deleted: z.boolean(),
organizationId: prefixedId('organization'),
orgLocationId: prefixedId('orgLocation'),
organizationId: prefixedId('organization').nullish().catch(undefined),
orgLocationId: prefixedId('orgLocation').optional().catch(undefined),
orgLocationOnly: z.boolean(),
})
.partial(),
})
.transform(({ data, id }) => Prisma.validator<Prisma.OrgWebsiteUpdateArgs>()({ where: { id }, data }))
.transform(({ data: { orgLocationId, organizationId, ...data }, id }) => {
return Prisma.validator<Prisma.OrgWebsiteUpdateArgs>()({
where: { id },
data: {
...data,
...(orgLocationId && {
locations: {
upsert: {
where: {
orgLocationId_orgWebsiteId: {
orgLocationId,
orgWebsiteId: id,
},
},
create: { orgLocationId },
update: { orgLocationId },
},
},
}),
...(organizationId && { organization: { connect: { id: organizationId } } }),
},
})
})
export type TUpdateSchema = z.infer<typeof ZUpdateSchema>
29 changes: 13 additions & 16 deletions packages/api/router/orgWebsite/query.forEditDrawer.handler.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
import { prisma } from '@weareinreach/db'
import { handleError } from '~api/lib/errorHandler'
import { type TRPCHandlerParams } from '~api/types/handler'

import { type TForEditDrawerSchema } from './query.forEditDrawer.schema'

export const forEditDrawer = async ({ input }: TRPCHandlerParams<TForEditDrawerSchema>) => {
try {
const result = await prisma.orgWebsite.findUnique({
where: input,
include: {
description: { include: { tsKey: true } },
},
})
if (!result) return null
const reformatted = {
...result,
description: result.description?.tsKey?.text,
}
return reformatted
} catch (error) {
handleError(error)
const result = await prisma.orgWebsite.findUnique({
where: input,
include: {
description: { include: { tsKey: true } },
},
})
if (!result) {
return null
}
const reformatted = {
...result,
description: result.description?.tsKey?.text,
}
return reformatted
}
export default forEditDrawer
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import { type TGetIdFromSlugSchema } from './query.getIdFromSlug.schema'
export const getIdFromSlug = async ({ ctx, input }: TRPCHandlerParams<TGetIdFromSlugSchema>) => {
const { slug } = input
const cachedId = await readSlugCache(slug)
if (cachedId) return { id: cachedId }
if (cachedId) {
return { id: cachedId }
}
const canSeeUnpublished =
ctx.session !== null &&
checkPermissions({
Expand Down
58 changes: 36 additions & 22 deletions packages/ui/components/data-display/ContactInfo/Websites.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Group, Menu, Stack, Text, Title, useMantineTheme } from '@mantine/core'
import { useTranslation } from 'next-i18next'
import { type ReactElement } from 'react'
import { type ReactElement, useCallback } from 'react'

import { isIdFor } from '@weareinreach/db/lib/idGen'
import { isExternal, Link } from '~ui/components/core/Link'
Expand All @@ -26,20 +26,28 @@ const WebsitesDisplay = ({ parentId = '', passedData, direct, locationOnly, webs
{ parentId, locationOnly },
{ enabled: !passedData }
)
// eslint-disable-next-line no-useless-escape
const domainExtract = /https?:\/\/([^:\/\n?]+)/

const componentData = passedData ? passedData : data
const domainExtract = /https?:\/\/([^:/\n?]+)/

if (!componentData?.length) return null
const componentData = passedData ?? data

if (!componentData?.length) {
return null
}

for (const website of componentData) {
const { id, url, orgLocationOnly, description, isPrimary } = website
const urlMatch = url.match(domainExtract)
const urlBase = urlMatch?.length ? urlMatch[1] : undefined
if (!isExternal(url)) continue
if (!urlBase) continue
if (locationOnly && !orgLocationOnly) continue
if (!isExternal(url)) {
continue
}
if (!urlBase) {
continue
}
if (locationOnly && !orgLocationOnly) {
continue
}

if (direct) {
return (
Expand All @@ -52,11 +60,10 @@ const WebsitesDisplay = ({ parentId = '', passedData, direct, locationOnly, webs
)
}

const desc = websiteDesc
? description?.key
const desc =
websiteDesc && description
? t(description.key, { ns: orgId?.id, defaultText: description.defaultText })
: urlBase
: urlBase
const item = (
<Link external key={id} href={url} variant={variants.Link.inline}>
{desc}
Expand All @@ -65,7 +72,9 @@ const WebsitesDisplay = ({ parentId = '', passedData, direct, locationOnly, webs
isPrimary ? output.unshift(item) : output.push(item)
}

if (!output.length) return null
if (!output.length) {
return null
}

return (
<Stack spacing={12}>
Expand Down Expand Up @@ -96,15 +105,19 @@ const WebsitesEdit = ({ parentId = '' }: WebsitesProps) => {
const linkToLocation = api.orgWebsite.locationLink.useMutation({
onSuccess: () => apiUtils.orgWebsite.invalidate(),
})
// eslint-disable-next-line no-useless-escape
const domainExtract = /https?:\/\/([^:\/\n?]+)/

const domainExtract = /https?:\/\/([^:/\n?]+)/

const output = data?.map((website) => {
const { id, url, description, published, deleted } = website
const urlMatch = url.match(domainExtract)
const urlBase = urlMatch?.length ? urlMatch[1] : undefined
if (!isExternal(url)) return null
if (!urlBase) return null
if (!isExternal(url)) {
return null
}
if (!urlBase) {
return null
}
const desc = description?.key
? t(description.key, { ns: orgId?.id, defaultText: description.defaultText })
: urlBase
Expand Down Expand Up @@ -135,6 +148,12 @@ const WebsitesEdit = ({ parentId = '' }: WebsitesProps) => {
)
return item
})
const handleLinkLocation = useCallback(
(orgWebsiteId: string) => () => {
linkToLocation.mutate({ orgWebsiteId, orgLocationId: parentId, action: 'link' })
},
[linkToLocation, parentId]
)

const addOrLink = isLocation ? (
<Menu keepMounted withinPortal>
Expand All @@ -161,12 +180,7 @@ const WebsitesEdit = ({ parentId = '' }: WebsitesProps) => {
? variants.Text.utility4darkGrayStrikethru
: variants.Text.utility4
return (
<Menu.Item
key={id}
onClick={() =>
linkToLocation.mutate({ orgLocationId: parentId, orgWebsiteId: id, action: 'link' })
}
>
<Menu.Item key={id} onClick={handleLinkLocation(id)}>
<Group noWrap>
<Icon icon='carbon:link' />
<Stack spacing={0}>
Expand Down
4 changes: 3 additions & 1 deletion packages/ui/components/data-display/ContactInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ export const ContactInfo = ({
}

export const hasContactInfo = (data: PassedDataObject | null | undefined): data is PassedDataObject => {
if (!data) return false
if (!data) {
return false
}
const { websites, phones, emails, socialMedia } = data
return Boolean(websites.length || phones.length || emails.length || socialMedia.length)
}
12 changes: 6 additions & 6 deletions packages/ui/components/data-display/Hours.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ export const Hours = ({ parentId, label = 'regular', edit, data: passedData }: H
<Text>Add opening hours</Text>
</Group>
) : (
<tbody>{hourTable}</tbody>
<Table>
<tbody>{hourTable}</tbody>
</Table>
)

return (
Expand All @@ -108,11 +110,9 @@ export const Hours = ({ parentId, label = 'regular', edit, data: passedData }: H
<Text variant={variants.Text.utility4darkGray}>{timezone}</Text>
</div>
{edit ? (
<Table>
<HoursDrawer locationId={parentId} component='a'>
{body}
</HoursDrawer>
</Table>
<HoursDrawer locationId={parentId} component='a'>
{body}
</HoursDrawer>
) : (
<Table>
<tbody>{hourTable}</tbody>
Expand Down
32 changes: 19 additions & 13 deletions packages/ui/components/data-portal/AddressDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { useDebouncedValue, useDisclosure } from '@mantine/hooks'
import compact from 'just-compact'
import filterObject from 'just-filter-object'
import { useTranslation } from 'next-i18next'
import { createContext, forwardRef, useContext, useEffect, useState } from 'react'
import { createContext, forwardRef, useCallback, useContext, useEffect, useState } from 'react'
import reactStringReplace from 'react-string-replace'
import { z } from 'zod'

Expand Down Expand Up @@ -250,13 +250,13 @@ const _AddressDrawer = forwardRef<HTMLButtonElement, AddressDrawerProps>(({ loca
setTimeout(() => handler.close(), 500)
},
})
function handleUpdate() {
const handleUpdate = useCallback(() => {
const changesOnly = filterObject(form.values.data, (key) => form.isDirty(`data.${key}`))

updateLocation.mutate(
FormSchema.transform(schemaTransform).parse({ id: form.values.id, data: changesOnly })
)
}
}, [form, updateLocation])

useEffect(() => {
if (isSaved && isSaved === form.isDirty()) {
Expand Down Expand Up @@ -329,17 +329,23 @@ const _AddressDrawer = forwardRef<HTMLButtonElement, AddressDrawerProps>(({ loca

// #region Dropdown item components/handling

function handleAutocompleteSelection(item: AutocompleteItem) {
if (!item.placeId) {
return
}
setGooglePlaceId(item.placeId)
}
const handleAutocompleteSelection = useCallback(
(item: AutocompleteItem) => {
if (!item.placeId) {
return
}
setGooglePlaceId(item.placeId)
},
[setGooglePlaceId]
)

function handleAutocompleteChange(val: string) {
setSearchTerm(val)
form.getInputProps('data.street1').onChange(val)
}
const handleAutocompleteChange = useCallback(
(val: string) => {
setSearchTerm(val)
form.getInputProps('data.street1').onChange(val)
},
[setSearchTerm, form]
)

// #endregion

Expand Down
Loading

0 comments on commit 06f1e88

Please sign in to comment.