From 5e81329dd6997aab41439df5b9955d4a213131a4 Mon Sep 17 00:00:00 2001 From: Joe Karow <58997957+JoeKarow@users.noreply.github.com> Date: Thu, 2 May 2024 17:37:16 -0400 Subject: [PATCH] refactor(IN-954): ActionButton component (#1205) # Pull Request type Please check the type of change your PR introduces: - [ ] Bugfix - [ ] Feature - [ ] Code style update (formatting, renaming) - [x] Refactoring (no functional changes, no API changes) - [ ] Build-related changes - [ ] Documentation content changes - [ ] Other (please describe): ## What is the current behavior? - This one component tries to do EVERYTHING. Issue Number: IN-954 ## What is the new behavior? - Separate out variants and use a compound component like `Badge` ## Does this introduce a breaking change? - [ ] Yes - [x] No ## Other information --------- Signed-off-by: InReach [bot] <108850934+InReach-svc@users.noreply.github.com> Signed-off-by: Joe Karow <58997957+JoeKarow@users.noreply.github.com> Co-authored-by: InReach [bot] <108850934+InReach-svc@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- apps/app/sentry.client.config.ts | 4 +- apps/app/sentry.edge.config.ts | 4 +- apps/app/sentry.server.config.ts | 4 +- .../pages/org/[slug]/[orgLocationId]/edit.tsx | 5 +- .../org/[slug]/[orgLocationId]/index.tsx | 5 +- apps/app/src/pages/org/[slug]/index.tsx | 3 +- .../organization/query.forOrgPage.handler.ts | 8 +- .../savedLists/mutation.deleteItem.handler.ts | 17 +- .../savedLists/mutation.deleteItem.schema.ts | 21 +- .../savedLists/mutation.saveItem.handler.ts | 17 +- .../savedLists/mutation.saveItem.schema.ts | 21 +- .../savedLists/query.isSaved.handler.ts | 2 +- packages/ui/.storybook/main.ts | 16 +- packages/ui/.storybook/preview.tsx | 11 +- packages/ui/.storybook/viewports.ts | 12 +- .../components/core/ActionButtons.stories.tsx | 114 ---- packages/ui/components/core/ActionButtons.tsx | 556 ------------------ .../components/core/ActionButtons/Group.tsx | 112 ++++ .../ui/components/core/ActionButtons/Menu.tsx | 110 ++++ .../components/core/ActionButtons/Print.tsx | 40 ++ .../components/core/ActionButtons/Review.tsx | 47 ++ .../ui/components/core/ActionButtons/Save.tsx | 241 ++++++++ .../components/core/ActionButtons/Share.tsx | 62 ++ .../core/ActionButtons/index.stories.tsx | 123 ++++ .../components/core/ActionButtons/index.tsx | 19 + .../components/core/ActionButtons/styles.ts | 74 +++ packages/ui/components/core/Breadcrumb.tsx | 2 +- packages/ui/components/core/Button.tsx | 12 +- .../ui/components/core/SearchResultCard.tsx | 3 +- packages/ui/components/core/Toolbar.tsx | 43 +- packages/ui/components/core/index.tsx | 1 - packages/ui/components/sections/Reviews.tsx | 2 +- .../components/sections/SuggestOrg/context.ts | 10 +- .../components/sections/SuggestOrg/index.tsx | 217 ++++--- .../components/sections/SuggestOrg/modals.tsx | 208 ++++--- packages/ui/icon/iconList.ts | 2 +- packages/ui/icon/index.tsx | 16 +- packages/ui/mockData/fieldOpt.ts | 127 +++- packages/ui/mockData/orgPhone.ts | 5 - packages/ui/modals/ModalTitle.tsx | 22 +- packages/ui/modals/QuickPromotion.tsx | 17 +- packages/ui/modals/Review.tsx | 7 +- packages/ui/theme/common.tsx | 4 +- 43 files changed, 1331 insertions(+), 1015 deletions(-) delete mode 100644 packages/ui/components/core/ActionButtons.stories.tsx delete mode 100644 packages/ui/components/core/ActionButtons.tsx create mode 100644 packages/ui/components/core/ActionButtons/Group.tsx create mode 100644 packages/ui/components/core/ActionButtons/Menu.tsx create mode 100644 packages/ui/components/core/ActionButtons/Print.tsx create mode 100644 packages/ui/components/core/ActionButtons/Review.tsx create mode 100644 packages/ui/components/core/ActionButtons/Save.tsx create mode 100644 packages/ui/components/core/ActionButtons/Share.tsx create mode 100644 packages/ui/components/core/ActionButtons/index.stories.tsx create mode 100644 packages/ui/components/core/ActionButtons/index.tsx create mode 100644 packages/ui/components/core/ActionButtons/styles.ts diff --git a/apps/app/sentry.client.config.ts b/apps/app/sentry.client.config.ts index 8e7ec58459..c8b81fe5ea 100644 --- a/apps/app/sentry.client.config.ts +++ b/apps/app/sentry.client.config.ts @@ -10,10 +10,10 @@ import { } from '@sentry/integrations' import * as Sentry from '@sentry/nextjs' -const isVercelProd = process.env.VERCEL_ENV === 'production' +const isVercel = process.env.VERCEL === '1' Sentry.init({ dsn: 'https://3398c2248c86498ab42fa8533e4f83f1@o1412293.ingest.us.sentry.io/6751163', - enabled: isVercelProd, + enabled: isVercel, // Setting this option to true will print useful information to the console while you're setting up Sentry. debug: !!process.env.SENTRY_DEBUG, diff --git a/apps/app/sentry.edge.config.ts b/apps/app/sentry.edge.config.ts index 5b84d4c7dc..321cb680ee 100644 --- a/apps/app/sentry.edge.config.ts +++ b/apps/app/sentry.edge.config.ts @@ -6,11 +6,11 @@ import * as Sentry from '@sentry/nextjs' -const isVercelProd = process.env.VERCEL_ENV === 'production' +const isVercel = process.env.VERCEL === '1' Sentry.init({ dsn: 'https://3398c2248c86498ab42fa8533e4f83f1@o1412293.ingest.us.sentry.io/6751163', - enabled: isVercelProd, + enabled: isVercel, // Adjust this value in production, or use tracesSampler for greater control tracesSampleRate: 0.5, diff --git a/apps/app/sentry.server.config.ts b/apps/app/sentry.server.config.ts index bd8009335f..7799cbe9c2 100644 --- a/apps/app/sentry.server.config.ts +++ b/apps/app/sentry.server.config.ts @@ -8,11 +8,11 @@ import { nodeProfilingIntegration } from '@sentry/profiling-node' import { prisma } from '@weareinreach/db' -const isVercelProd = process.env.VERCEL_ENV === 'production' +const isVercel = process.env.VERCEL === '1' Sentry.init({ dsn: 'https://3398c2248c86498ab42fa8533e4f83f1@o1412293.ingest.us.sentry.io/6751163', - enabled: isVercelProd, + enabled: isVercel, debug: !!process.env.SENTRY_DEBUG, // Tracing rates tracesSampleRate: 0.5, diff --git a/apps/app/src/pages/org/[slug]/[orgLocationId]/edit.tsx b/apps/app/src/pages/org/[slug]/[orgLocationId]/edit.tsx index 5f2c82f6cc..f55bd72fa8 100644 --- a/apps/app/src/pages/org/[slug]/[orgLocationId]/edit.tsx +++ b/apps/app/src/pages/org/[slug]/[orgLocationId]/edit.tsx @@ -53,9 +53,7 @@ const OrgLocationPage: NextPage {hasAlerts && diff --git a/apps/app/src/pages/org/[slug]/[orgLocationId]/index.tsx b/apps/app/src/pages/org/[slug]/[orgLocationId]/index.tsx index 5da0064e75..81b928c280 100644 --- a/apps/app/src/pages/org/[slug]/[orgLocationId]/index.tsx +++ b/apps/app/src/pages/org/[slug]/[orgLocationId]/index.tsx @@ -48,9 +48,7 @@ const OrgLocationPage: NextPage = () => { { id: orgLocationId }, { enabled: router.isReady } ) - const { data: isSaved } = api.savedList.isSaved.useQuery(orgData?.id as string, { - enabled: orgDataStatus === 'success' && Boolean(orgData?.id), - }) + const { data: alertData } = api.location.getAlerts.useQuery( { id: orgLocationId }, { enabled: router.isReady } @@ -110,7 +108,6 @@ const OrgLocationPage: NextPage = () => { }, }} organizationId={orgData.id} - saved={Boolean(isSaved)} /> {hasAlerts && diff --git a/apps/app/src/pages/org/[slug]/index.tsx b/apps/app/src/pages/org/[slug]/index.tsx index 24a1a58ea7..9b35231716 100644 --- a/apps/app/src/pages/org/[slug]/index.tsx +++ b/apps/app/src/pages/org/[slug]/index.tsx @@ -135,7 +135,7 @@ const OrganizationPage = ({ return } - const { userLists, attributes, description, reviews, locations, isClaimed, id: organizationId } = data + const { attributes, description, reviews, locations, isClaimed, id: organizationId } = data const body = locations?.length <= 1 ? ( @@ -185,7 +185,6 @@ const OrganizationPage = ({ option: 'back', backTo: 'search', }} - saved={Boolean(userLists?.length)} organizationId={organizationId} /> diff --git a/packages/api/router/organization/query.forOrgPage.handler.ts b/packages/api/router/organization/query.forOrgPage.handler.ts index 3f9b0c470f..91aacfbfad 100644 --- a/packages/api/router/organization/query.forOrgPage.handler.ts +++ b/packages/api/router/organization/query.forOrgPage.handler.ts @@ -4,7 +4,7 @@ import { type TRPCHandlerParams } from '~api/types/handler' import { type TForOrgPageSchema } from './query.forOrgPage.schema' -const forOrgPage = async ({ ctx, input }: TRPCHandlerParams) => { +const forOrgPage = async ({ input }: TRPCHandlerParams) => { const { slug } = input const org = await prisma.organization.findUniqueOrThrow({ where: { @@ -19,12 +19,6 @@ const forOrgPage = async ({ ctx, input }: TRPCHandlerParams) lastVerified: true, allowedEditors: { where: { authorized: true }, select: { userId: true } }, description: freeText, - userLists: ctx.session?.user.id - ? { - where: { list: { ownedById: ctx.session.user.id } }, - select: { list: { select: { id: true, name: true } } }, - } - : undefined, reviews: { where: { visible: true, deleted: false }, diff --git a/packages/api/router/savedLists/mutation.deleteItem.handler.ts b/packages/api/router/savedLists/mutation.deleteItem.handler.ts index c608e3345d..c72a127305 100644 --- a/packages/api/router/savedLists/mutation.deleteItem.handler.ts +++ b/packages/api/router/savedLists/mutation.deleteItem.handler.ts @@ -1,4 +1,4 @@ -import { getAuditedClient } from '@weareinreach/db' +import { getAuditedClient, isIdFor } from '@weareinreach/db' import { checkListOwnership } from '~api/lib/checkListOwnership' import { type TRPCHandlerParams } from '~api/types/handler' @@ -6,7 +6,7 @@ import { type TDeleteItemSchema } from './mutation.deleteItem.schema' const deleteItem = async ({ ctx, input }: TRPCHandlerParams) => { const prisma = getAuditedClient(ctx.actorId) - const { id, organizationId, serviceId } = input + const { id, itemId } = input checkListOwnership({ listId: id, userId: ctx.session.user.id }) const result = await prisma.userSavedList.update({ @@ -16,30 +16,27 @@ const deleteItem = async ({ ctx, input }: TRPCHandlerParams Boolean(organizationId ?? serviceId ?? itemId), { + message: 'Must provide either organizationId, serviceId, or itemId', + }) + .transform(({ id, organizationId, serviceId, itemId }) => { + if (itemId !== undefined) { + return { id, itemId } + } + return { id, itemId: (organizationId ?? serviceId) as string } + }) export type TDeleteItemSchema = z.infer diff --git a/packages/api/router/savedLists/mutation.saveItem.handler.ts b/packages/api/router/savedLists/mutation.saveItem.handler.ts index e90d98f9f7..036e17961d 100644 --- a/packages/api/router/savedLists/mutation.saveItem.handler.ts +++ b/packages/api/router/savedLists/mutation.saveItem.handler.ts @@ -1,4 +1,4 @@ -import { getAuditedClient } from '@weareinreach/db' +import { getAuditedClient, isIdFor } from '@weareinreach/db' import { checkListOwnership } from '~api/lib/checkListOwnership' import { type TRPCHandlerParams } from '~api/types/handler' @@ -6,7 +6,7 @@ import { type TSaveItemSchema } from './mutation.saveItem.schema' const saveItem = async ({ ctx, input }: TRPCHandlerParams) => { const prisma = getAuditedClient(ctx.actorId) - const { id, organizationId, serviceId } = input + const { id, itemId } = input checkListOwnership({ listId: id, userId: ctx.session.user.id }) @@ -16,24 +16,21 @@ const saveItem = async ({ ctx, input }: TRPCHandlerParams Boolean(organizationId ?? serviceId ?? itemId), { + message: 'Must provide either organizationId, serviceId, or itemId', + }) + .transform(({ id, organizationId, serviceId, itemId }) => { + if (itemId !== undefined) { + return { id, itemId } + } + return { id, itemId: (organizationId ?? serviceId) as string } + }) export type TSaveItemSchema = z.infer diff --git a/packages/api/router/savedLists/query.isSaved.handler.ts b/packages/api/router/savedLists/query.isSaved.handler.ts index c67a18c462..f38ba44d9a 100644 --- a/packages/api/router/savedLists/query.isSaved.handler.ts +++ b/packages/api/router/savedLists/query.isSaved.handler.ts @@ -26,7 +26,7 @@ const isSaved = async ({ ctx, input }: TRPCHandlerParams) => { }, }) if (!result.length) { - return false + return null } return result } diff --git a/packages/ui/.storybook/main.ts b/packages/ui/.storybook/main.ts index d8fb696a3d..b920212ec2 100644 --- a/packages/ui/.storybook/main.ts +++ b/packages/ui/.storybook/main.ts @@ -20,7 +20,7 @@ const getAbsolutePath = (value: string) => { const publicStatic = path.resolve(__dirname, '../../../apps/app/public') -const config: StorybookConfig = { +const storybookConfig: StorybookConfig = { stories: [ '../components/**/*.stories.{ts,tsx}', '../hooks/**/*.stories.{ts,tsx}', @@ -41,12 +41,12 @@ const config: StorybookConfig = { getAbsolutePath('@storybook/addon-essentials'), getAbsolutePath('@geometricpanda/storybook-addon-badges'), getAbsolutePath('@storybook/addon-a11y'), - // eslint-disable-next-line storybook/no-uninstalled-addons - '@tomfreudenberg/next-auth-mock/storybook', // This addon doesn't like to be wrapped. getAbsolutePath('@storybook/addon-designs'), getAbsolutePath('storybook-addon-pseudo-states'), getAbsolutePath('@storybook/addon-interactions'), '@storybook/addon-webpack5-compiler-swc', + // eslint-disable-next-line storybook/no-uninstalled-addons + '@tomfreudenberg/next-auth-mock/storybook', // This addon doesn't like to be wrapped. ], framework: { name: '@storybook/nextjs', @@ -105,7 +105,7 @@ const config: StorybookConfig = { stats: { colors: true, }, - devtool: options.configType === 'DEVELOPMENT' ? 'eval-source-map' : undefined, + // devtool: options.configType === 'DEVELOPMENT' ? 'eval-source-map' : undefined, } /** I18 HMR */ @@ -113,7 +113,11 @@ const config: StorybookConfig = { const plugin = new I18NextHMRPlugin({ localesDir: path.resolve(__dirname, '../../../apps/app/public/locales'), }) - Array.isArray(config.plugins) ? config.plugins.push(plugin) : (config.plugins = [plugin]) + if (Array.isArray(config.plugins)) { + config.plugins.push(plugin) + } else { + config.plugins = [plugin] + } } const mergedConfig = mergeAndConcat(config, configAdditions) @@ -131,4 +135,4 @@ const config: StorybookConfig = { STORYBOOK_PROJECT_ROOT: path.resolve(__dirname, '../'), }, } -export default config +export default storybookConfig diff --git a/packages/ui/.storybook/preview.tsx b/packages/ui/.storybook/preview.tsx index 2532169539..023da8cce4 100644 --- a/packages/ui/.storybook/preview.tsx +++ b/packages/ui/.storybook/preview.tsx @@ -1,6 +1,7 @@ import './wdyr' import './font.css' import { type BADGE } from '@geometricpanda/storybook-addon-badges' +import { type ViewportAddonParameter } from '@storybook/addon-viewport' import { type Preview } from '@storybook/react' import { type WhyDidYouRenderOptions } from '@welldone-software/why-did-you-render' import { http, passthrough, type RequestHandler } from 'msw' @@ -24,7 +25,7 @@ import { WithWhyDidYouRender, } from './decorators' import { i18n } from './i18next' -import { viewport, type ViewportConfig } from './viewports' +import { viewport } from './viewports' import type authStates from './mockAuthStates' @@ -35,7 +36,7 @@ initializeMsw({ }, }, onUnhandledRequest: ({ method, url }) => { - if (url.startsWith('/trpc' || '/api')) { + if (url.startsWith('/trpc') || url.startsWith('/api')) { console.error(`Unhandled ${method} request to ${url}. This exception has been only logged in the console, however, it's strongly recommended to resolve this error as you don't want unmocked data in Storybook stories. @@ -64,8 +65,6 @@ const preview: Preview = { excludeDecorators: true, }, }, - i18n, - viewport, chromatic: { delay: 1000, }, @@ -80,6 +79,8 @@ const preview: Preview = { }), }, }, + i18n, + viewport, }, globalTypes: { ...i18NextGlobalTypes, @@ -110,7 +111,7 @@ declare module '@storybook/react' { } locale?: LocaleCodes i18n?: typeof i18n - viewport?: ViewportConfig + viewport?: ViewportAddonParameter design?: DesignParams | DesignParams[] msw?: RequestHandler[] | { handlers: RequestHandler[] | Record } nextAuthMock?: { session: keyof typeof authStates } diff --git a/packages/ui/.storybook/viewports.ts b/packages/ui/.storybook/viewports.ts index b9f8ef3f04..791d750514 100644 --- a/packages/ui/.storybook/viewports.ts +++ b/packages/ui/.storybook/viewports.ts @@ -1,14 +1,6 @@ -import { type INITIAL_VIEWPORTS } from '@storybook/addon-viewport' +import { type ViewportAddonParameter } from '@storybook/addon-viewport' -import { type Viewports } from './types' - -type ViewportMap = typeof INITIAL_VIEWPORTS -export interface ViewportConfig { - viewports?: ViewportMap - defaultViewport?: Viewports -} - -export const viewport: ViewportConfig = { +export const viewport: ViewportAddonParameter = { viewports: { iphonex: { name: 'iPhone X', diff --git a/packages/ui/components/core/ActionButtons.stories.tsx b/packages/ui/components/core/ActionButtons.stories.tsx deleted file mode 100644 index 29d62dd9bf..0000000000 --- a/packages/ui/components/core/ActionButtons.stories.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import { type Meta, type StoryObj } from '@storybook/react' - -import { getTRPCMock } from '~ui/lib/getTrpcMock' -import { organization } from '~ui/mockData/organization' -import { review } from '~ui/mockData/review' -import { savedList } from '~ui/mockData/savedList' - -import { ActionButtons as ActionButtonsComponent } from './ActionButtons' - -export default { - title: 'Design System/Action Buttons', - component: ActionButtonsComponent, - parameters: { - design: { - type: 'figma', - url: 'https://www.figma.com/file/gl8ppgnhpSq1Dr7Daohk55/Design-System-(2023)?node-id=52%3A1420&t=sleVeGl2lJv7Df18-4', - }, - layout: 'fullscreen', - layoutWrapper: 'centeredHalf', - msw: [ - organization.getIdFromSlug, - review.create, - savedList.getAll, - savedList.saveItem, - savedList.createAndSaveItem, - ], - nextjs: { - router: { - pathname: '/org/[slug]', - asPath: '/org/mockOrg', - query: { - slug: 'mockOrg', - }, - }, - }, - }, -} satisfies Meta - -type StoryDef = StoryObj - -export const Save = { - parameters: { - nextAuthMock: { - session: 'userPic', - }, - }, - args: { - iconKey: 'save', - }, -} - -export const SaveLoggedOut = { - parameters: { - nextAuthMock: { - session: 'noAuth', - }, - }, - args: { - iconKey: 'save', - }, -} satisfies StoryDef - -export const SavedToSingleList = { - args: { - iconKey: 'save', - }, - parameters: { - nextAuthMock: { - session: 'userPic', - }, - msw: [savedList.isSavedSingle, savedList.deleteItem, organization.getIdFromSlug], - }, -} satisfies StoryDef -export const SavedToMultipleLists = { - args: { - iconKey: 'save', - }, - parameters: { - nextAuthMock: { - session: 'userPic', - }, - msw: [savedList.isSavedMultiple, savedList.getAll, savedList.deleteItem, organization.getIdFromSlug], - }, -} satisfies StoryDef -export const Share = { - args: { - iconKey: 'share', - }, -} satisfies StoryDef -export const Print = { - args: { - iconKey: 'print', - }, -} satisfies StoryDef -export const Delete = { - args: { - iconKey: 'delete', - }, -} satisfies StoryDef -export const Review = { - args: { - iconKey: 'review', - }, -} satisfies StoryDef -export const More = { - parameters: { - nextAuthMock: { - session: 'userPic', - }, - }, - args: { - iconKey: 'more', - }, -} satisfies StoryDef diff --git a/packages/ui/components/core/ActionButtons.tsx b/packages/ui/components/core/ActionButtons.tsx deleted file mode 100644 index 5374a76d38..0000000000 --- a/packages/ui/components/core/ActionButtons.tsx +++ /dev/null @@ -1,556 +0,0 @@ -import { - Box, - Button, - type ButtonProps, - Center, - createPolymorphicComponent, - createStyles, - Group, - Loader, - Menu, - rem, - Skeleton, - Text, - useMantineTheme, -} from '@mantine/core' -import { useClipboard } from '@mantine/hooks' -import { useRouter } from 'next/router' -import { useSession } from 'next-auth/react' -import { useTranslation } from 'next-i18next' -import { type ComponentType, forwardRef, type JSX, useState } from 'react' - -import { type ApiInput } from '@weareinreach/api' -import { useNewNotification, useScreenSize } from '~ui/hooks' -import { Icon } from '~ui/icon' -import { trpc as api } from '~ui/lib/trpcClient' -import { CreateNewList } from '~ui/modals/CreateNewList' -import { QuickPromotionModal } from '~ui/modals/QuickPromotion' -import { ReviewModal } from '~ui/modals/Review' - -const useStyles = createStyles((theme) => ({ - button: { - display: 'flex', - flexDirection: 'row', - alignItems: 'center', - minWidth: rem(48), - height: rem(48), - padding: rem(12), - gap: rem(8), - backgroundColor: theme.other.colors.secondary.white, - border: 0, - borderRadius: rem(8), - '&:not([data-disabled])': theme.fn.hover({ - backgroundColor: theme.other.colors.primary.lightGray, - }), - }, - buttonPressed: { - display: 'flex', - flexDirection: 'row', - alignItems: 'center', - minWidth: rem(48), - height: rem(48), - padding: rem(12), - gap: rem(8), - backgroundColor: theme.other.colors.primary.lightGray, - '&:not([data-disabled])': theme.fn.hover({ - backgroundColor: theme.other.colors.primary.lightGray, - }), - }, - icon: {}, - text: { - fontWeight: theme.other.fontWeight.semibold, - marginLeft: rem(8), - }, - dropdown: { - background: theme.other.colors.secondary.black, - borderRadius: theme.radius.md, - paddingTop: rem(2), - paddingBottom: rem(2), - }, - item: { - '& > *': { - color: 'white !important', - }, - color: 'white', - fontWeight: theme.other.fontWeight.semibold, - fontSize: theme.fontSizes.md, - '&[data-hovered]': { - backgroundColor: 'inherit', - // color: 'black', - textDecoration: 'underline', - }, - }, -})) - -export const actionButtonIcons = { - save: { - icon: 'carbon:favorite', - labelKey: 'words.save', - }, - share: { icon: 'carbon:share', labelKey: 'words.share' }, - print: { icon: 'carbon:printer', labelKey: 'words.print' }, - review: { icon: 'carbon:star', labelKey: 'words.review' }, - delete: { icon: 'carbon:delete', labelKey: 'words.delete' }, - more: { - icon: 'carbon:overflow-menu-horizontal', - useMenu: true, - }, -} as const - -/** - * Returns a Menu Item with the new of an existing list. When clicked it saves the current organization or - * service to the list. - * - * @param data - Contains information about the list - * @param data.id - List id : string - * @param data.organizationId - String | undefined - * @param data.serviceId - String | undefined - * @param name - List name : string - * @returns JSX.Element - */ -const ListItem = ({ data, name, action }: ListMenuProps) => { - const { t } = useTranslation() - const utils = api.useUtils() - - const savedInList = useNewNotification({ - icon: 'heartFilled', - displayText: t('list.added', { name }), - }) - const errorSaving = useNewNotification({ - icon: 'warning', - displayText: t('list.error-add'), - }) - const deletedInList = useNewNotification({ - icon: 'heartEmpty', - displayText: t('list.removedMulti', { name }), - }) - const errorRemoving = useNewNotification({ - icon: 'warning', - displayText: t('list.error-remove'), - }) - - const saveItem = api.savedList.saveItem.useMutation({ - onSuccess: (_, { organizationId, serviceId }) => { - savedInList() - utils.savedList.isSaved.invalidate(serviceId ?? organizationId) - }, - onError: errorSaving, - }) - const removeItem = api.savedList.deleteItem.useMutation({ - onSuccess: (_, { organizationId, serviceId }) => { - deletedInList() - utils.savedList.isSaved.invalidate(serviceId ?? organizationId) - }, - onError: errorRemoving, - }) - const clickHandler = () => { - if (action === 'save') { - saveItem.mutate(data) - } else { - removeItem.mutate(data) - } - } - - return clickHandler()}>{name} -} - -export const SaveToggleButton = forwardRef( - ({ omitLabel, serviceId, organizationId, isMenu, ...rest }, ref) => { - const [isSaved, setIsSaved] = useState(false) - const [opened, setOpened] = useState(false) - const [singleListId, setSingleListId] = useState() - const [singleListName, setSingleListName] = useState() - const [menuChildren, setMenuChildren] = useState( - -
- -
-
- ) - const { classes } = useStyles() - const { status: sessionStatus } = useSession() - const { t } = useTranslation('common') - const theme = useMantineTheme() - const utils = api.useUtils() - const buttonIcon = isSaved ? 'carbon:favorite-filled' : 'carbon:favorite' - - api.savedList.isSaved.useQuery(serviceId ?? (organizationId as string), { - enabled: sessionStatus === 'authenticated' && Boolean(organizationId || serviceId), - refetchOnWindowFocus: false, - onSuccess: (data) => { - setIsSaved(Boolean(data)) - if (!data) return - if (data.length === 1) { - const record = data[0] - setMenuChildren(null) - if (!record) return - setSingleListId(record.id) - setSingleListName(record.name) - return - } - setMenuChildren( - data.map(({ id, name }) => ( - - )) - ) - }, - }) - const savedLists = api.savedList.getAll.useQuery(undefined, { - refetchOnWindowFocus: false, - enabled: sessionStatus === 'authenticated', - onError: () => { - if (isSaved) return - setMenuChildren( - savedLists.refetch()} closeMenuOnClick={false}> -
{t('retry')}
-
- ) - }, - onSuccess: (data) => { - if (isSaved) return - setMenuChildren( - data ? ( - [ - - {t('list.create-new')} - , - ...data.map(({ id, name }) => ( - - )), - ] - ) : ( - - {t('list.create-new')} - - ) - ) - }, - }) - const deletedInList = useNewNotification({ - icon: 'heartEmpty', - displayText: t('list.removedMulti', { name: singleListName }), - }) - const errorRemoving = useNewNotification({ - icon: 'warning', - displayText: t('list.error-remove'), - }) - const removeItem = api.savedList.deleteItem.useMutation({ - onSuccess: () => { - deletedInList() - utils.savedList.isSaved.invalidate(serviceId ?? organizationId) - setIsSaved(false) - utils.savedList.getAll.invalidate() - }, - onError: errorRemoving, - }) - - let ButtonInner = ( - <> - - {!omitLabel && ( - - {t(isSaved ? 'words.saved' : 'words.save')} - - )} - - ) - - if (isMenu) ButtonInner = {ButtonInner} - - // BUG: [IN-808] "Save" not receving correct styles when it's in the overflow menu. - if (sessionStatus !== 'authenticated') { - if (isMenu) - return ( - - {ButtonInner} - - ) - return ( - - {ButtonInner} - - ) - } - - if (isSaved && singleListId) { - return ( - - - - ) - } - return ( - - - - {ButtonInner} - - - {menuChildren} - - ) - } -) -SaveToggleButton.displayName = 'SaveToggleButton' - -const SaveButton = createPolymorphicComponent<'button', SaveToggleButtonProps>(SaveToggleButton) - -/** - * Polymorphic component, returns a button. When clicked saves the current url to the clients clipboard - * - * @returns Polymorphic button component - */ -const CopyToClipBoard = forwardRef((props, ref) => { - const { t } = useTranslation() - const { asPath } = useRouter() - const clipboard = useClipboard({ timeout: 500 }) - const copiedToClipboard = useNewNotification({ icon: 'info', displayText: t('link-copied') }) - /** Strip out unused props to prevent react errors */ - const { organizationId: _org, serviceId: _serv, isMenu: _isMenu, ...restProps } = props - - const handleCopy = () => { - const href = `${window.location.origin}${asPath}` - clipboard.copy(href) - copiedToClipboard() - } - - return -}) - -CopyToClipBoard.displayName = 'CopyToClipboard' - -const ShareLink = createPolymorphicComponent<'button', PolyButtonProps>(CopyToClipBoard) - -/** - * Polymorphic element, returns a button. When clicked takes a screenshot of the current client view - * - * @returns Polymorphic button component - */ -const PrintBody = forwardRef((props, ref) => { - /** Strip out unused props to prevent react errors */ - const { organizationId: _org, serviceId: _serv, isMenu: _isMenu, ...restProps } = props - return window.print()} {...restProps} /> -}) - -PrintBody.displayName = 'Print' - -const PrintButton = createPolymorphicComponent<'button', PolyButtonProps>(PrintBody) - -// TODO: [IN-786] Associate ActionButton click actions - -// Previous actions object is now a hook to check user session before using save or saved actions -const useActions = () => { - const { classes } = useStyles() - const { status: sessionStatus } = useSession() - /** - * Curried function which accepts a Polymorphic button element as its base param. The inner function returns - * a JSX component. - * - * @param Component - Accepts the return value of the createPolymorphicComponent function - * @param isMenu - Boolean. If true, the component prop for the Polymorphic element will be Menu.Item, else - * it will be Button - * @param children - JSX.Element - * @param props - ButtonProps. Its main use is to handle component styling - * @returns A function which returns a JSX.Element - */ - const generic = (Component: Polymorphic | ComponentType) => { - const action = ({ isMenu, children, props }: Generic) => { - if (isMenu) - return ( - - {children} - - ) - - return ( - - {children} - - ) - } - return action - } - - return { - // TODO: assign behaviour to delete button - delete: generic(QuickPromotionModal), - more: generic(createPolymorphicComponent<'button', PolyButtonProps>(Button)), - print: generic(PrintButton), - review: generic(sessionStatus === 'authenticated' ? ReviewModal : QuickPromotionModal), - save: generic(SaveToggleButton), - share: generic(ShareLink), - } as const -} - -/** - * Used to display the action buttons when viewing an organization/location/service. - * - * When using the save or unsave buttons for services, you need to pass the serviceId prop. - * - * When trying to save or unsave an organization, the component parses the current URL to find the - * organization's id, so you don't need to pass it as a prop. - */ -export const ActionButtons = ({ - iconKey, - omitLabel = false, - serviceId, - organizationId, - outsideMoreMenu, - children, -}: ActionButtonProps) => { - const { classes } = useStyles() - const theme = useMantineTheme() - const { t } = useTranslation() - const iconRender = actionButtonIcons[iconKey] - const { more: _, ...overFlowItems } = actionButtonIcons - const actions = useActions() - const [opened, setOpened] = useState(false) - const { query: rawQuery } = useRouter() - const { slug } = rawQuery - const { isMobile, isTablet } = useScreenSize() - - const { data: orgQuery } = api.organization.getIdFromSlug.useQuery( - { slug: slug as string }, - { enabled: typeof slug === 'string' } - ) - - const orgId = orgQuery?.id || organizationId - - const orgOrServiceId = { organizationId: orgId ?? '', serviceId } - - let filteredOverflowItems = Object.entries(overFlowItems).filter( - ([key, _item]) => !(isMobile || isTablet) || key !== 'print' - ) - - if (outsideMoreMenu) - /* Keep overFlowItems where the key is not in outsideMoreMenu array */ - filteredOverflowItems = filteredOverflowItems.filter(([key, _item]) => !outsideMoreMenu.includes(key)) - - const overflowMenuItems = filteredOverflowItems.map(([key, item]) => { - const children = ( - - - {t(item.labelKey)} - - ) - - return actions[key as keyof typeof actionButtonIcons]({ - isMenu: true, - children, - props: { ...orgOrServiceId, key }, - }) - }) - - const menuThings = overflowMenuItems - - const buttonProps = { - className: opened ? classes.buttonPressed : classes.button, - radius: 'md', - ...orgOrServiceId, - } - - /** The button component */ - const buttonIcon = ( - <> - - {!omitLabel && 'labelKey' in iconRender && ( - {children ? children : t(iconRender.labelKey, { count: 1 })} - )} - - ) - - const buttonComponent = actions[iconKey]({ children: buttonIcon, props: buttonProps }) - - /** The menu component */ - const menuComponent = ( - - {buttonComponent} - {menuThings} - - ) - - return 'useMenu' in iconRender ? menuComponent : buttonComponent -} -const Loading = () => - -ActionButtons.Loading = Loading - -interface ActionButtonProps { - /** - * The action button is created using an iconKey, which, depending on the value supplied, will display - * either an icon and a label or just an icon - */ - iconKey: keyof typeof actionButtonIcons - /** Display icon only */ - omitLabel?: boolean - /** Specify which buttons will be displayed in the 'more' dropdown menu */ - outsideMoreMenu?: string[] - children?: string - /** Information for save button */ - serviceId?: string - organizationId?: string -} - -type Polymorphic = typeof QuickPromotionModal | typeof ReviewModal | typeof SaveButton - -type PropAdditions = { serviceId?: string; organizationId: string; key?: string; isMenu?: boolean } - -type PolymorphicProps = ButtonProps & PropAdditions -type PolyButtonProps = ButtonProps & Partial - -type Generic = { - children?: JSX.Element - isMenu?: boolean - props?: PolyButtonProps | PolymorphicProps -} - -export interface SaveToggleButtonProps extends Omit { - organizationId?: string - serviceId?: string - isMenu?: boolean -} - -type ListMenuProps = SaveMenuProps | DeleteMenuProps -interface SaveMenuProps extends ButtonProps { - data: ApiInput['savedList']['saveItem'] - name: string - action: 'save' -} -interface DeleteMenuProps extends ButtonProps { - data: ApiInput['savedList']['deleteItem'] - name: string - action: 'delete' -} diff --git a/packages/ui/components/core/ActionButtons/Group.tsx b/packages/ui/components/core/ActionButtons/Group.tsx new file mode 100644 index 0000000000..2d5f8966b5 --- /dev/null +++ b/packages/ui/components/core/ActionButtons/Group.tsx @@ -0,0 +1,112 @@ +import { Box, createStyles } from '@mantine/core' +import { Children, cloneElement, type ReactElement, useCallback, useEffect, useRef, useState } from 'react' + +import { OverflowMenu } from './Menu' + +const useStyles = createStyles(() => ({ + visible: { + order: 0, + visibility: 'visible', + opacity: 1, + }, + inVisible: { + order: 100, + visibility: 'hidden', + pointerEvents: 'none', + }, + groupWrapper: { + display: 'flex', + overflow: 'hidden', + flexWrap: 'nowrap', + maxWidth: '100%', + }, + overflowStyle: { + order: 99, + position: 'sticky', + right: 0, + }, +})) + +const isHTMLElement = (e: unknown): e is HTMLElement => e instanceof HTMLElement + +const getTargetId = (e: ReactElement) => { + const targetId = typeof e.props['data-targetid'] === 'string' && e.props['data-targetid'] + if (!targetId) { + return null + } + return targetId +} + +export const ActionButtonGroup = ({ children }: ActionButtonGroupProps) => { + const { classes, cx } = useStyles() + const containerRef = useRef(null) + const [visibilityMap, setVisibilityMap] = useState>({}) + const handleIntersection: IntersectionObserverCallbackFn = useCallback((entries) => { + const updatedEntries: Record = {} + entries.forEach((entry) => { + if (isHTMLElement(entry.target)) { + const targetid = entry.target.dataset.targetid + if (!targetid) { + return + } + if (entry.isIntersecting) { + updatedEntries[targetid] = true + } else { + updatedEntries[targetid] = false + } + } + }) + + setVisibilityMap((prev) => ({ + ...prev, + ...updatedEntries, + })) + }, []) + useEffect(() => { + const observer = new IntersectionObserver(handleIntersection, { + root: containerRef.current, + threshold: 1, + }) + + // We are addting observers to child elements of the container div + // with ref as navRef. Notice that we are adding observers + // only if we have the data attribute observerid on the child elemeent + containerRef.current && + Array.from(containerRef.current.children).forEach((item) => { + if (isHTMLElement(item) && item.dataset.targetid) { + observer.observe(item) + } + }) + return () => observer.disconnect() + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + return ( + + {...Children.map(children, (child) => { + const targetId = getTargetId(child) + if (!targetId) { + return child + } + const isVisible = visibilityMap[targetId] ?? false + const clonedChild = cloneElement(child, { + ...child.props, + className: cx(child.props.className, { + [classes.visible]: isVisible, + [classes.inVisible]: !isVisible, + }), + }) + return clonedChild + })} + + {children} + + + ) +} + +interface ActionButtonGroupProps { + children: ReactElement | ReactElement[] +} + +type IntersectionObserverCallbackFn = ConstructorParameters[0] diff --git a/packages/ui/components/core/ActionButtons/Menu.tsx b/packages/ui/components/core/ActionButtons/Menu.tsx new file mode 100644 index 0000000000..ae1c3144b9 --- /dev/null +++ b/packages/ui/components/core/ActionButtons/Menu.tsx @@ -0,0 +1,110 @@ +import { Menu, type MenuProps, useMantineTheme } from '@mantine/core' +import { + Children, + cloneElement, + forwardRef, + isValidElement, + type MouseEventHandler, + type ReactElement, + useCallback, + useMemo, + useState, +} from 'react' + +import { Button } from '~ui/components/core/Button' +import { Icon, type IconifyIconHTMLElement } from '~ui/icon' + +import { useStyles } from './styles' + +const getTargetId = (e: ReactElement) => { + const targetId = typeof e.props['data-targetid'] === 'string' && e.props['data-targetid'] + if (!targetId) { + return null + } + return targetId +} + +export const OverflowMenu = forwardRef( + ({ children, className, visibilityMap, ...props }, ref) => { + const { classes, cx } = useStyles() + const theme = useMantineTheme() + const [anchorEl, setAnchorEl] = useState< + (EventTarget & IconifyIconHTMLElement) | (EventTarget & HTMLElement) | null + >(null) + const open = Boolean(anchorEl) + + const handleClick: MouseEventHandler & MouseEventHandler = + useCallback( + (event) => { + setAnchorEl(event.currentTarget) + }, + [setAnchorEl] + ) + + const handleClose = useCallback(() => { + setAnchorEl(null) + }, [setAnchorEl]) + + const shouldShowMenu = useMemo( + () => Object.values(visibilityMap).some((v) => v === false), + [visibilityMap] + ) + + if (!shouldShowMenu) { + return null + } + const { inOverflowMenu: _inOverflowMenu, ...menuClassNames } = classes + return ( + + + + + + {Children.map(children, (child) => { + const targetId = getTargetId(child as ReactElement) + if (isValidElement(child) && targetId && !visibilityMap[targetId]) { + const clonedElement = cloneElement(child, { + className: cx(child.props.className, classes.inOverflowMenu, classes.item), + }) + + return ( + + {clonedElement} + + ) + } + + return null + })} + + + ) + } +) +OverflowMenu.displayName = 'ActionButtons.Menu' + +export interface ActionButtonMenuProps extends MenuProps { + className: string + visibilityMap: Record +} diff --git a/packages/ui/components/core/ActionButtons/Print.tsx b/packages/ui/components/core/ActionButtons/Print.tsx new file mode 100644 index 0000000000..766697b63f --- /dev/null +++ b/packages/ui/components/core/ActionButtons/Print.tsx @@ -0,0 +1,40 @@ +import { Box, Group, Text, useMantineTheme } from '@mantine/core' +import { useTranslation } from 'next-i18next' +import { forwardRef } from 'react' + +import { Button, type ButtonProps } from '~ui/components/core/Button' +import { Icon } from '~ui/icon' + +import { useStyles } from './styles' + +export const Print = forwardRef(({ omitLabel, className, ...props }, ref) => { + const { classes, cx } = useStyles() + const theme = useMantineTheme() + const { t } = useTranslation('common') + + return ( + + + + {!omitLabel && {t('words.print')}} + + + ) +}) +Print.displayName = 'ActionButtons.Print' + +export interface PrintProps extends ButtonProps { + omitLabel?: boolean +} diff --git a/packages/ui/components/core/ActionButtons/Review.tsx b/packages/ui/components/core/ActionButtons/Review.tsx new file mode 100644 index 0000000000..44008216e8 --- /dev/null +++ b/packages/ui/components/core/ActionButtons/Review.tsx @@ -0,0 +1,47 @@ +import { Box, Group, Text, useMantineTheme } from '@mantine/core' +import { useSession } from 'next-auth/react' +import { useTranslation } from 'next-i18next' +import { forwardRef, useMemo } from 'react' + +import { type ButtonProps } from '~ui/components/core/Button' +import { Icon } from '~ui/icon' +import { QuickPromotionModal } from '~ui/modals/QuickPromotion' +import { ReviewModal } from '~ui/modals/Review' + +import { useStyles } from './styles' + +export const Review = forwardRef( + ({ omitLabel, className, ...props }, ref) => { + const { classes, cx } = useStyles() + const theme = useMantineTheme() + const { t } = useTranslation('common') + const { status: sessionStatus } = useSession() + + const BaseComponent = useMemo(() => { + if (sessionStatus === 'authenticated') { + return ReviewModal + } + return QuickPromotionModal + }, [sessionStatus]) + + return ( + + + + {!omitLabel && {t('words.review')}} + + + ) + } +) +Review.displayName = 'ActionButtons.Review' + +export interface ReviewProps extends ButtonProps { + omitLabel?: boolean +} diff --git a/packages/ui/components/core/ActionButtons/Save.tsx b/packages/ui/components/core/ActionButtons/Save.tsx new file mode 100644 index 0000000000..921b2e5cc8 --- /dev/null +++ b/packages/ui/components/core/ActionButtons/Save.tsx @@ -0,0 +1,241 @@ +import { Box, Center, Group, Menu, Text, useMantineTheme } from '@mantine/core' +import { useDisclosure } from '@mantine/hooks' +import { useSession } from 'next-auth/react' +import { useTranslation } from 'next-i18next' +import { type ComponentPropsWithRef, forwardRef, useCallback, useMemo } from 'react' + +import { type ApiInput } from '@weareinreach/api' +import { Button, type ButtonProps } from '~ui/components/core/Button' +import { useNewNotification } from '~ui/hooks/useNewNotification' +import { Icon } from '~ui/icon' +import { trpc as api } from '~ui/lib/trpcClient' +import { CreateNewList } from '~ui/modals' +import { QuickPromotionModal } from '~ui/modals/QuickPromotion' + +import { useStyles } from './styles' + +const useNotifications = (listName: string) => { + const { t } = useTranslation('common') + + return { + saved: useNewNotification({ + icon: 'heartFilled', + displayText: t('list.added', { name: listName }), + }), + deleted: useNewNotification({ + icon: 'heartEmpty', + displayText: t('list.removedMulti', { name: listName }), + }), + errorSave: useNewNotification({ + icon: 'warning', + displayText: t('list.error-add'), + }), + errorDelete: useNewNotification({ + icon: 'warning', + displayText: t('list.error-remove'), + }), + } +} + +/** + * Returns a Menu Item with the new of an existing list. When clicked it saves the current organization or + * service to the list. + * + * @param data - Contains information about the list + * @param data.id - List id : string + * @param data.organizationId - String | undefined + * @param data.serviceId - String | undefined + * @param name - List name : string + * @returns JSX.Element + */ +const ListItem = ({ data, name, action }: ListMenuProps) => { + const { t } = useTranslation() + const utils = api.useUtils() + + const savedInList = useNewNotification({ + icon: 'heartFilled', + displayText: t('list.added', { name }), + }) + const errorSaving = useNewNotification({ + icon: 'warning', + displayText: t('list.error-add'), + }) + const deletedInList = useNewNotification({ + icon: 'heartEmpty', + displayText: t('list.removedMulti', { name }), + }) + const errorRemoving = useNewNotification({ + icon: 'warning', + displayText: t('list.error-remove'), + }) + + const saveItem = api.savedList.saveItem.useMutation({ + onSuccess: (_, { itemId }) => { + savedInList() + utils.savedList.isSaved.invalidate(itemId) + }, + onError: errorSaving, + }) + const removeItem = api.savedList.deleteItem.useMutation({ + onSuccess: (_, { itemId }) => { + deletedInList() + utils.savedList.isSaved.invalidate(itemId) + }, + onError: errorRemoving, + }) + const clickHandler = useCallback(() => { + if (action === 'save') { + saveItem.mutate(data) + } else { + removeItem.mutate(data) + } + }, [action, data, removeItem, saveItem]) + + return {name} +} + +export const Save = forwardRef( + ({ itemId, itemName, menuItem, omitLabel, className, ...rest }, ref) => { + const [menuOpened, menuHandler] = useDisclosure(false) + const { classes, cx } = useStyles() + const { status: sessionStatus } = useSession() + const { t } = useTranslation('common') + const utils = api.useUtils() + const notifications = useNotifications(itemName) + const theme = useMantineTheme() + + const userIsLoggedIn = useMemo(() => sessionStatus === 'authenticated', [sessionStatus]) + + const { data: savedToLists } = api.savedList.isSaved.useQuery(itemId, { + enabled: userIsLoggedIn, + }) + const { + data: availableLists, + isError: availableListsError, + refetch: refetchAvailableLists, + } = api.savedList.getAll.useQuery(undefined, { + refetchOnWindowFocus: false, + enabled: sessionStatus === 'authenticated', + }) + const removeItem = api.savedList.deleteItem.useMutation({ + onSuccess: () => { + notifications.deleted() + utils.savedList.isSaved.invalidate(itemId) + utils.savedList.getAll.invalidate() + }, + onError: notifications.errorDelete, + }) + + const isSaved = Boolean(savedToLists) + const isLoggedIn = sessionStatus === 'authenticated' + const buttonIcon = isSaved ? 'carbon:favorite-filled' : 'carbon:favorite' + const savedToSingleList = savedToLists && savedToLists.length === 1 + + const baseClassname = menuItem ? undefined : classes.button + const iconColor = menuItem ? theme.other.colors.secondary.white : theme.other.colors.secondary.black + + const modalProps: ComponentPropsWithRef = menuItem + ? { ref, component: Menu.Item, radius: 'md' } + : { ref, component: Button, className: classes.button, radius: 'md' } + + const handleRemoveFromList = useCallback( + (listId: string) => () => removeItem.mutate({ id: listId, itemId }), + [itemId, removeItem] + ) + const handleRefetchAvailableLists = useCallback(() => refetchAvailableLists(), [refetchAvailableLists]) + + const DisplayedInfo = ( + + + {!omitLabel && ( + + {t(isSaved ? 'words.saved' : 'words.save')} + + )} + + ) + + if (!isLoggedIn) { + return ( + + {DisplayedInfo} + + ) + } + + if (isSaved && savedToSingleList) { + const listId = savedToLists.at(0)?.id + + if (!listId) { + return <>Error + } + + return ( + + {DisplayedInfo} + + ) + } + + return ( + + + + {DisplayedInfo} + + + + {availableListsError ? ( + +
{t('words.retry')}
+
+ ) : ( + <> + {t('list.create-new')} + {availableLists?.map(({ id, name }) => ( + + ))} + + )} +
+
+ ) + } +) +Save.displayName = 'ActionButtons.Save' + +export interface ActionButtonSaveProps extends ButtonProps { + itemId: string + itemName: string + menuItem?: boolean + omitLabel?: boolean +} + +type ListMenuProps = SaveMenuProps | DeleteMenuProps +interface SaveMenuProps extends ButtonProps { + data: ApiInput['savedList']['saveItem'] + name: string + action: 'save' +} +interface DeleteMenuProps extends ButtonProps { + data: ApiInput['savedList']['deleteItem'] + name: string + action: 'delete' +} diff --git a/packages/ui/components/core/ActionButtons/Share.tsx b/packages/ui/components/core/ActionButtons/Share.tsx new file mode 100644 index 0000000000..ac05a0949a --- /dev/null +++ b/packages/ui/components/core/ActionButtons/Share.tsx @@ -0,0 +1,62 @@ +import { Box, Group, Text, useMantineTheme } from '@mantine/core' +import { useClipboard } from '@mantine/hooks' +import { useRouter } from 'next/router' +import { useTranslation } from 'next-i18next' +import { forwardRef, useCallback } from 'react' + +import { Button, type ButtonProps } from '~ui/components/core/Button' +import { useNewNotification } from '~ui/hooks' +import { Icon } from '~ui/icon' + +import { useStyles } from './styles' + +export const Share = forwardRef(({ omitLabel, className, ...props }, ref) => { + const { classes, cx } = useStyles() + const theme = useMantineTheme() + const { t } = useTranslation('common') + const { asPath } = useRouter() + const href = `${window.location.origin}${asPath}` + + const clipboard = useClipboard({ timeout: 500 }) + const copiedToClipboard = useNewNotification({ icon: 'info', displayText: t('link-copied') }) + + const handleCopy = useCallback(async () => { + if (navigator.canShare instanceof Function && navigator?.canShare?.({ url: href })) { + try { + await navigator.share({ url: href }) + } catch { + clipboard.copy(href) + copiedToClipboard() + } + } else { + clipboard.copy(href) + copiedToClipboard() + } + }, [clipboard, copiedToClipboard, href]) + + return ( + + + + {!omitLabel && {t('words.share')}} + + + ) +}) +Share.displayName = 'ActionButtons.Share' + +export interface ShareProps extends ButtonProps { + omitLabel?: boolean +} diff --git a/packages/ui/components/core/ActionButtons/index.stories.tsx b/packages/ui/components/core/ActionButtons/index.stories.tsx new file mode 100644 index 0000000000..0dc436ac96 --- /dev/null +++ b/packages/ui/components/core/ActionButtons/index.stories.tsx @@ -0,0 +1,123 @@ +import { type Meta, type StoryObj } from '@storybook/react' + +import { organization } from '~ui/mockData/organization' +import { review } from '~ui/mockData/review' +import { savedList } from '~ui/mockData/savedList' + +import { ActionButtons as ActionButtonsComponent } from './index' + +export default { + title: 'Design System/Action Buttons', + component: ActionButtonsComponent, + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/gl8ppgnhpSq1Dr7Daohk55/Design-System-(2023)?node-id=52%3A1420&t=sleVeGl2lJv7Df18-4', + }, + layout: 'fullscreen', + layoutWrapper: 'centeredHalf', + msw: [ + organization.getIdFromSlug, + review.create, + savedList.getAll, + savedList.saveItem, + savedList.createAndSaveItem, + ], + nextjs: { + router: { + pathname: '/org/[slug]', + asPath: '/org/mockOrg', + query: { + slug: 'mockOrg', + }, + }, + }, + nextAuthMock: { session: 'noAuth' }, + }, +} satisfies Meta + +type StoryDef = StoryObj + +export const Save = { + parameters: { + nextAuthMock: { + session: 'userPic', + }, + }, + args: { itemId: 'orgn_1234', itemName: 'Test item name' }, + render: (args) => , +} satisfies StoryObj + +export const SaveLoggedOut = { + parameters: { + nextAuthMock: { + session: 'noAuth', + }, + }, + args: { itemId: 'orgn_1234', itemName: 'Test item name' }, + render: (args) => , +} satisfies StoryObj + +export const SavedToSingleList = { + parameters: { + nextAuthMock: { + session: 'userPic', + }, + msw: [savedList.isSavedSingle, savedList.deleteItem, organization.getIdFromSlug], + }, + args: { itemId: 'orgn_1234', itemName: 'Test item name' }, + render: (args) => , +} satisfies StoryObj +export const SavedToMultipleLists = { + parameters: { + nextAuthMock: { + session: 'userPic', + }, + msw: [savedList.isSavedMultiple, savedList.getAll, savedList.deleteItem, organization.getIdFromSlug], + }, + args: { itemId: 'orgn_1234', itemName: 'Test item name' }, + render: (args) => , +} satisfies StoryObj +export const Share = { + render: (args) => , +} satisfies StoryObj +export const Print = { + render: (args) => , +} satisfies StoryObj +export const Delete = { + args: { + iconKey: 'delete', + }, +} satisfies StoryDef +export const Review = { + render: (args) => , +} satisfies StoryObj +export const More = { + parameters: { + nextAuthMock: { + session: 'userPic', + }, + }, + args: { + containerWidth: 100, + }, + argTypes: { + containerWidth: { + control: 'range', + min: 1, + max: 100, + step: 5, + }, + }, + // @ts-expect-error Stop yelling about the `containerWidth` prop. + render: ({ containerWidth }: { containerWidth: number }) => ( +
+ + + + + + +
+ ), +} satisfies StoryObj diff --git a/packages/ui/components/core/ActionButtons/index.tsx b/packages/ui/components/core/ActionButtons/index.tsx new file mode 100644 index 0000000000..96d20c15f7 --- /dev/null +++ b/packages/ui/components/core/ActionButtons/index.tsx @@ -0,0 +1,19 @@ +import { Skeleton } from '@mantine/core' + +import { ActionButtonGroup } from './Group' +import { OverflowMenu } from './Menu' +import { Print } from './Print' +import { Review } from './Review' +import { Save } from './Save' +import { Share } from './Share' + +const Loading = () => +export const ActionButtons = () => null + +ActionButtons.Loading = Loading +ActionButtons.Save = Save +ActionButtons.Share = Share +ActionButtons.Print = Print +ActionButtons.Review = Review +ActionButtons.Menu = OverflowMenu +ActionButtons.Group = ActionButtonGroup diff --git a/packages/ui/components/core/ActionButtons/styles.ts b/packages/ui/components/core/ActionButtons/styles.ts new file mode 100644 index 0000000000..158daa93fb --- /dev/null +++ b/packages/ui/components/core/ActionButtons/styles.ts @@ -0,0 +1,74 @@ +import { createStyles, rem } from '@mantine/core' + +export const useStyles = createStyles((theme) => ({ + button: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + // minWidth: rem(48), + minWidth: 'fit-content', + height: rem(48), + padding: rem(12), + gap: rem(8), + backgroundColor: theme.other.colors.secondary.white, + border: 0, + borderRadius: rem(8), + '&:not([data-disabled])': theme.fn.hover({ + backgroundColor: theme.other.colors.primary.lightGray, + }), + }, + buttonPressed: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + minWidth: rem(48), + height: rem(48), + padding: rem(12), + gap: rem(8), + backgroundColor: theme.other.colors.primary.lightGray, + '&:not([data-disabled])': theme.fn.hover({ + backgroundColor: theme.other.colors.primary.lightGray, + }), + }, + icon: { + color: theme.other.colors.secondary.black, + }, + text: { + fontWeight: theme.other.fontWeight.semibold, + marginLeft: rem(8), + }, + dropdown: { + background: theme.other.colors.secondary.black, + borderRadius: theme.radius.md, + paddingTop: rem(2), + paddingBottom: rem(2), + }, + item: { + '& > *': { + color: 'white !important', + }, + color: 'white', + fontWeight: theme.other.fontWeight.semibold, + fontSize: theme.fontSizes.md, + '&[data-hovered]': { + backgroundColor: 'inherit', + // color: 'black', + textDecoration: 'underline', + }, + }, + inOverflowMenu: { + border: 'none !important', + padding: 0, + backgroundColor: 'inherit', + ...theme.fn.hover({ + backgroundColor: 'transparent !important', + }), + height: 'unset', + '&.mantine-Group-root, .mantine-Text-root, .iconify-icon-root, .mantine-Menu-item': { + color: theme.other.colors.secondary.white, + // ...theme.fn.hover({ + // backgroundColor: 'transparent !important', + // }), + }, + }, +})) diff --git a/packages/ui/components/core/Breadcrumb.tsx b/packages/ui/components/core/Breadcrumb.tsx index ab8842e128..6b0e26b658 100644 --- a/packages/ui/components/core/Breadcrumb.tsx +++ b/packages/ui/components/core/Breadcrumb.tsx @@ -119,7 +119,7 @@ export const Breadcrumb = (props: BreadcrumbProps) => { return ( - + >( +export const Button = forwardRef>( (props, ref) => { const isCustom = (customVariants as ReadonlyArray).includes(props.variant ?? 'filled') const { classes: baseClasses } = useVariantStyles({ variant: props.variant ?? 'filled' }) - const { children, variant, classNames, ...others } = props as ButtonProps + const { children, variant, classNames, ...others } = props as MantineButtonProps const mantineVariant = isCustom ? undefined : (variant as ButtonVariant) @@ -192,12 +192,8 @@ Button.displayName = '@weareinreach/ui/components/core/Button' interface ButtonStylesParams { variant?: CustomVariants | 'filled' | 'outline' } -// type MantineButtonProps = Pick< -// ButtonProps, -// 'type' | 'fullWidth' | 'uppercase' | 'loaderProps' | 'loaderPosition' -// > -interface CustomButtonProps extends ButtonProps { +export interface ButtonProps extends MantineButtonProps { /** Button style/design */ variant?: CustomVariants | 'filled' | 'outline' /** Label Text */ diff --git a/packages/ui/components/core/SearchResultCard.tsx b/packages/ui/components/core/SearchResultCard.tsx index bbb40733b8..f8fb37f610 100644 --- a/packages/ui/components/core/SearchResultCard.tsx +++ b/packages/ui/components/core/SearchResultCard.tsx @@ -157,6 +157,7 @@ const SearchResultData = ({ result }: SearchResultHasData) => { className={classes.hoverText} {...(hovered && { 'data-hovered': hovered })} mb={12} + {...(hovered && { 'data-hovered': hovered })} > { {leaderBadgeGroup} - + ({ toolbar: { // padding: `${rem(0)} ${rem(8)} ${rem(0)} ${rem(12)}`, @@ -14,41 +10,26 @@ const useStyles = createStyles(() => ({ }, })) -export const Toolbar = ({ saved = false, breadcrumbProps, hideBreadcrumb, ...ids }: Props) => { - const theme = useMantineTheme() - const isMobile = useMediaQuery(`(max-width: ${theme.breakpoints.sm})`) - const { width } = useViewportSize() +export const Toolbar = ({ breadcrumbProps, hideBreadcrumb, ...ids }: Props) => { const { classes } = useStyles() - const buttons = ['review', 'share', 'save'] - - const buttonsInViewPort = isMobile ? Math.ceil((width - BREACRUMB_WIDTH) / MIN_BUTTON_WIDTH) % 3 : 4 - - /* Contains the actionButtons displayed outside the 'more' actionButton menu */ - const inToolbar = buttonsInViewPort > 3 ? buttons : buttons.slice(-(buttonsInViewPort + 1)) - - const displayButtons = inToolbar.map((button) => ( - - )) - - // If organization is not saved do not display saved button - if (!saved) inToolbar.push('saved') - - // No delete button in toolbar - inToolbar.push('delete') return ( {hideBreadcrumb ? : } - - {displayButtons} - - + + + + + ) } type Props = { - saved: boolean breadcrumbProps: BreadcrumbProps organizationId: string serviceId?: string diff --git a/packages/ui/components/core/index.tsx b/packages/ui/components/core/index.tsx index 4ebc965d65..8ff028db7e 100644 --- a/packages/ui/components/core/index.tsx +++ b/packages/ui/components/core/index.tsx @@ -1,5 +1,4 @@ // codegen:start {preset: barrel, include: ./*.ts*, exclude: "*.stories.*"} -export * from './ActionButtons' export * from './AlertMessage' export * from './AntiHateMessage' export * from './Breadcrumb' diff --git a/packages/ui/components/sections/Reviews.tsx b/packages/ui/components/sections/Reviews.tsx index 3972b6ccbe..7e3f0787e3 100644 --- a/packages/ui/components/sections/Reviews.tsx +++ b/packages/ui/components/sections/Reviews.tsx @@ -62,7 +62,7 @@ export const ReviewSection = (props: ReviewSectionProps) => { {t('review', { count: 2 })} - {t('add', { ns: 'common', item: '$t(review)' })} + {t('add', { ns: 'common', item: '$t(review)' })} {Boolean(props.reviews.length) && } {props.reviews.length ? reviews : noReviews} diff --git a/packages/ui/components/sections/SuggestOrg/context.ts b/packages/ui/components/sections/SuggestOrg/context.ts index 7e8be02e0d..a07af900b3 100644 --- a/packages/ui/components/sections/SuggestOrg/context.ts +++ b/packages/ui/components/sections/SuggestOrg/context.ts @@ -1,7 +1,5 @@ import { createFormContext } from '@mantine/form' -import { type ApiOutput } from '@weareinreach/api' - export const [SuggestionFormProvider, useFormContext, useForm] = createFormContext() export interface SuggestionForm { //data for submission @@ -19,11 +17,5 @@ export interface SuggestionForm { communityFocus?: string[] //supportive data - communityParent?: string[] - searchLocation: string - locationOptions: { - value: string - placeId: string - }[] - formOptions: ApiOutput['organization']['suggestionOptions'] + // communityParent?: string[] } diff --git a/packages/ui/components/sections/SuggestOrg/index.tsx b/packages/ui/components/sections/SuggestOrg/index.tsx index eaf9525478..aa4119b1a5 100644 --- a/packages/ui/components/sections/SuggestOrg/index.tsx +++ b/packages/ui/components/sections/SuggestOrg/index.tsx @@ -1,5 +1,6 @@ import { Autocomplete, + type AutocompleteItem, Button, createStyles, Divider, @@ -19,9 +20,12 @@ import { Trans, useTranslation } from 'next-i18next' import { type ComponentPropsWithRef, type Dispatch, + type FocusEventHandler, forwardRef, type SetStateAction, + useCallback, useEffect, + useMemo, useState, } from 'react' @@ -94,9 +98,17 @@ interface SuggestOrgProps { const OrgExistsError = ({ queryResult, form, setGenerateSlug }: OrgExistsErrorProps) => { const variants = useCustomVariant() - if (!queryResult) return null + const handleDismiss = useCallback(() => { + form.clearFieldError('orgName') + setGenerateSlug(true) + }, [form, setGenerateSlug]) + + if (!queryResult) { + return null + } const { name, published, slug } = queryResult const key = published ? 'form.error-exists-active' : 'form.error-exists-inactive' + return ( <> { - form.clearFieldError('orgName') - setGenerateSlug(true) - }} - > + . ), @@ -148,78 +154,79 @@ export const SuggestOrg = ({ authPromptState }: SuggestOrgProps) => { const { t } = useTranslation(['suggestOrg', 'services', 'attribute']) const simpleLocale = (locale: string) => (locale.length === 2 ? locale : locale.substring(0, 1)) const variants = useCustomVariant() - const [locationSearch, setLocationSearch] = useState('') + const [placeId, setPlaceId] = useState('') const [loading, setLoading] = useState(true) - const [locSearchInput] = useDebouncedValue(form.values.searchLocation, 400) + const [searchLocation, setSearchLocation] = useState('') + const [locSearchInput] = useDebouncedValue(searchLocation, 400) const [orgName, setOrgName] = useState() const [generateSlug, setGenerateSlug] = useState(false) const router = useRouter() const countrySelected = Boolean(form.values.countryId) - const { - data: formOptions, - isLoading, - isSuccess, - } = api.organization.suggestionOptions.useQuery(undefined, { - onSuccess: (data) => { - form.setValues({ formOptions: data }) - }, - }) + const { data: formOptions, isLoading, isSuccess } = api.organization.suggestionOptions.useQuery() - api.geo.autocomplete.useQuery( + const { data: addressCandidates } = api.geo.autocomplete.useQuery( { search: locSearchInput, locale: simpleLocale(router.locale), fullAddress: true }, { enabled: Boolean(locSearchInput) && locSearchInput !== '', - onSuccess: ({ results }) => - form.setValues({ - locationOptions: results.map((result) => ({ - value: `${result.value}, ${result.subheading}`, - label: `${result.value}, ${result.subheading}`, - placeId: result.placeId, - })), - }), refetchOnWindowFocus: false, } ) - api.geo.geoByPlaceId.useQuery(locationSearch, { - enabled: Boolean(locationSearch) && locationSearch !== '', - onSuccess: ({ result }) => { - if (result) - form.setFieldValue('orgAddress', { - street1: `${result.streetNumber} ${result.streetName}`, - city: result.city, - govDist: result.govDist, - postCode: result.postCode, - }) - }, + const addressAutocompleteOptions = useMemo( + () => + addressCandidates?.results.map((result) => ({ + value: `${result.value}, ${result.subheading}`, + label: `${result.value}, ${result.subheading}`, + placeId: result.placeId, + })) ?? [], + [addressCandidates] + ) + + const { data: addressResult } = api.geo.geoByPlaceId.useQuery(placeId, { + enabled: Boolean(placeId) && placeId !== '', }) + useEffect(() => { + if (addressResult?.result) { + const { result } = addressResult + form.setFieldValue('orgAddress', { + street1: `${result.streetNumber} ${result.streetName}`, + city: result.city, + govDist: result.govDist, + postCode: result.postCode, + }) + } + }, [addressResult, form]) - api.organization.checkForExisting.useQuery(orgName ?? '', { + const { data: existingOrg } = api.organization.checkForExisting.useQuery(orgName ?? '', { enabled: Boolean(orgName && orgName !== ''), - onSuccess: (data) => { - if (!data) { - form.clearFieldError('orgName') - setGenerateSlug(true) - } else { - form.setFieldError('orgName', ) - } - }, }) - api.organization.generateSlug.useQuery(orgName ?? '', { + useEffect(() => { + if (!existingOrg && !generateSlug) { + form.clearFieldError('orgName') + setGenerateSlug(true) + } else if (existingOrg) { + form.setFieldError( + 'orgName', + + ) + } + }, [existingOrg, generateSlug, form]) + + const { data: generatedSlug } = api.organization.generateSlug.useQuery(orgName ?? '', { enabled: Boolean(orgName && orgName !== '' && generateSlug), - onSuccess: (data) => { - if (data) form.setFieldValue('orgSlug', data) - setGenerateSlug(false) - }, }) + useEffect(() => { + if (generatedSlug) { + form.setFieldValue('orgSlug', generatedSlug) + setGenerateSlug(false) + } + }, [form, generatedSlug]) useEffect(() => { if (loading && formOptions && isSuccess && !isLoading) { - form.setValues({ formOptions }) setLoading(false) } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [loading, formOptions, isSuccess, isLoading]) useEffect(() => { @@ -227,27 +234,56 @@ export const SuggestOrg = ({ authPromptState }: SuggestOrgProps) => { setOverlay(true) form.setFieldValue('countryId', '') } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [hasAuth, overlay, form.values.countryId]) + }, [hasAuth, overlay, form.values.countryId, form, setOverlay]) - if (loading) return null + const countryTranslation = useMemo( + () => + new Intl.DisplayNames([router.locale.toLowerCase()], { + type: 'region', + }), + [router.locale] + ) - const countryTranslation = new Intl.DisplayNames([router.locale.toLowerCase()], { - type: 'region', - }) + const countrySelections = useMemo( + () => + Array.isArray(formOptions?.countries) + ? formOptions.countries.map(({ id, cca2 }) => { + return + }) + : null, + [formOptions?.countries, countryTranslation] + ) - const countrySelections = Array.isArray(form.values.formOptions?.countries) - ? form.values.formOptions?.countries.map(({ id, cca2 }, i) => { - return ( - - ) - }) - : null + const handleOrgNameBlur = useCallback>( + (e) => { + setOrgName(e.target.value) + }, + [setOrgName] + ) + + const handleAddressSelection = useCallback( + (e: AutocompleteItem) => { + setPlaceId(e.placeId) + }, + [setPlaceId] + ) + + const handleDismiss = useCallback(() => { + form.setValues({ + communityFocus: [], + // communityParent: [], + countryId: '', + orgName: '', + orgSlug: '', + orgWebsite: '', + orgAddress: {}, + }) + modalHandler.close() + }, [form, modalHandler]) + if (loading) { + return null + } return (
suggestOrgApi.mutate(form.values))}> @@ -273,15 +309,15 @@ export const SuggestOrg = ({ authPromptState }: SuggestOrgProps) => { setOrgName(e.target.value)} + onBlur={handleOrgNameBlur} /> @@ -292,18 +328,17 @@ export const SuggestOrg = ({ authPromptState }: SuggestOrgProps) => { } - placeholder={t('form.placeholder-address') as string} + placeholder={t('form.placeholder-address')} disabled={!countrySelected} - onItemSubmit={(e) => { - setLocationSearch(e.placeId) - }} - {...form.getInputProps('searchLocation')} + onItemSubmit={handleAddressSelection} + value={searchLocation} + onChange={setSearchLocation} /> - - + + diff --git a/packages/ui/components/sections/SuggestOrg/modals.tsx b/packages/ui/components/sections/SuggestOrg/modals.tsx index 6031a7eff6..d61c12887b 100644 --- a/packages/ui/components/sections/SuggestOrg/modals.tsx +++ b/packages/ui/components/sections/SuggestOrg/modals.tsx @@ -1,37 +1,59 @@ -import { Button, Checkbox, Divider, Modal, Stack, Text, Title } from '@mantine/core' +import { Button, Checkbox, createStyles, Divider, Group, Modal, rem, Stack, Text, Title } from '@mantine/core' import { useDisclosure } from '@mantine/hooks' import { useTranslation } from 'next-i18next' +import { type ReactNode, useCallback, useMemo } from 'react' +import { type ApiOutput } from '@weareinreach/api' import { useCustomVariant } from '~ui/hooks/useCustomVariant' import { ModalTitle } from '~ui/modals/ModalTitle' import { useFormContext } from './context' +const useStyles = createStyles((theme) => ({ + count: { + ...theme.other.utilityFonts.utility1, + background: theme.other.colors.secondary.black, + borderRadius: '100%', + color: theme.other.colors.secondary.white, + width: rem(24), + height: rem(24), + textAlign: 'center', + display: 'inline-block', + verticalAlign: 'center', + lineHeight: 1.5, + }, +})) interface ModalProps { disabled: boolean } +interface ServiceModalProps extends ModalProps { + serviceTypes: NonNullable['serviceTypes'] +} -export const ServiceTypes = ({ disabled }: ModalProps) => { +export const ServiceTypes = ({ disabled, serviceTypes }: ServiceModalProps) => { + const { classes } = useStyles() const form = useFormContext() const variants = useCustomVariant() - const [open, handler] = useDisclosure(false) + const [modalOpen, modalHandler] = useDisclosure(false) const { t } = useTranslation(['suggestOrg', 'services']) - const options = Array.isArray(form.values.formOptions?.serviceTypes) - ? form.values.formOptions?.serviceTypes.map((item, i) => ( - - )) - : null + const options = useMemo( + () => + serviceTypes.map((item) => ( + + )), + [serviceTypes, t] + ) + const selectedCountIcon = useMemo(() => { + const selectedServices = form.values.serviceCategories?.length ?? 0 + return selectedServices > 0 ? {selectedServices} : null + }, [classes.count, form.values.serviceCategories?.length]) return ( <> handler.close()} - title={} + opened={modalOpen} + onClose={modalHandler.close} + title={} scrollAreaComponent={Modal.NativeScrollArea} > @@ -44,7 +66,7 @@ export const ServiceTypes = ({ disabled }: ModalProps) => { - @@ -55,66 +77,96 @@ export const ServiceTypes = ({ disabled }: ModalProps) => { ) } -export const Communities = ({ disabled }: ModalProps) => { +interface CommunitiesModalProps extends ModalProps { + communities: NonNullable['communities'] +} + +export const Communities = ({ disabled, communities }: CommunitiesModalProps) => { + const { classes } = useStyles() const form = useFormContext() const variants = useCustomVariant() - const [open, handler] = useDisclosure(false) + const [modalOpen, modalHandler] = useDisclosure(false) const { t } = useTranslation(['suggestOrg', 'attribute']) - const selectedCurr = form.values.communityFocus ?? [] - // const childRecords = form.values.formOptions?.communities.flatMap(({ children }) => children) + const selectedCurr = useMemo(() => form.values.communityFocus ?? [], [form.values.communityFocus]) const unique = (ids: string[]) => [...new Set(ids)] - const hasChildren = (parentId: string) => - form.values.formOptions?.communities.find(({ id, children }) => id === parentId && children.length) + const selectedCountIcon = useMemo(() => { + const selectedItems = form.values.communityFocus?.length ?? 0 + return selectedItems > 0 ? {selectedItems} : null + }, [classes.count, form.values.communityFocus?.length]) + + const hasChildren = useCallback( + (parentId: string) => communities.find(({ id, children }) => id === parentId && children.length), + [communities] + ) - const getChildIds = (parentId: string) => { - const parentRecord = form.values.formOptions?.communities.find(({ id }) => id === parentId) - if (!parentRecord) return [] - return parentRecord.children.map(({ id }) => id) - } + const getChildIds = useCallback( + (parentId: string) => { + const parentRecord = communities.find(({ id }) => id === parentId) + return parentRecord?.children.map(({ id }) => id) ?? [] + }, + [communities] + ) - const selectedChildren = (parentId: string, all?: boolean, none?: boolean): boolean => { - const parentRecord = form.values.formOptions?.communities.find(({ id }) => id === parentId) - if (!parentRecord || !hasChildren(parentId)) return false - if (all) { - const allChecked = parentRecord.children.every(({ id }) => selectedCurr.includes(id)) - return allChecked - } - if (none) { - const noneChecked = parentRecord.children.every(({ id }) => !selectedCurr.includes(id)) - return noneChecked - } - return Boolean( - !selectedChildren(parentId, true) && parentRecord.children.some(({ id }) => selectedCurr.includes(id)) - ) - } - const toggleCategory = (parentId: string) => { - const parentRecord = form.values.formOptions?.communities.find(({ id }) => id === parentId) - if (!parentRecord) return - const childIds = getChildIds(parentId) - if (selectedChildren(parentId, true)) { - // all selected -> deselect all - form.setFieldValue( - 'communityFocus', - selectedCurr.filter((id) => !childIds.includes(id)) + const selectedChildren = useCallback( + (parentId: string, all?: boolean, none?: boolean): boolean => { + const parentRecord = communities.find(({ id }) => id === parentId) + if (!parentRecord || !hasChildren(parentId)) { + return false + } + if (all) { + const allChecked = parentRecord.children.every(({ id }) => selectedCurr.includes(id)) + return allChecked + } + if (none) { + const noneChecked = parentRecord.children.every(({ id }) => !selectedCurr.includes(id)) + return noneChecked + } + return Boolean( + !selectedChildren(parentId, true) && parentRecord.children.some(({ id }) => selectedCurr.includes(id)) ) - return - } - form.setFieldValue('communityFocus', unique([...selectedCurr, ...childIds])) - return - } + }, + [communities, hasChildren, selectedCurr] + ) + const toggleCategory = useCallback( + (parentId: string) => { + const parentRecord = communities.find(({ id }) => id === parentId) + if (!parentRecord) { + return void 0 + } + const childIds = getChildIds(parentId) + if (selectedChildren(parentId, true)) { + // all selected -> deselect all + form.setFieldValue( + 'communityFocus', + selectedCurr.filter((id) => !childIds.includes(id)) + ) + return void 0 + } + form.setFieldValue('communityFocus', unique([...selectedCurr, ...childIds])) + return void 0 + }, + [communities, form, getChildIds, selectedChildren, selectedCurr] + ) + const handleCategoryToggle = useCallback((id: string) => () => toggleCategory(id), [toggleCategory]) + + const wrapInStack = useCallback((children: ReactNode) => {children}, []) - const options = Array.isArray(form.values.formOptions?.communities) - ? form.values.formOptions?.communities.map((item, par) => { + const options = useMemo( + () => + communities.map((item, par) => { if (item.children.length) { const indeterminate = selectedChildren(item.id) const checked = selectedChildren(item.id, true) @@ -124,19 +176,16 @@ export const Communities = ({ disabled }: ModalProps) => { label={`${item.icon} ${t(item.tsKey, { ns: item.tsNs })}`} indeterminate={indeterminate} checked={checked} - onClick={() => toggleCategory(item.id)} + onClick={handleCategoryToggle(item.id)} // onChange={() => noop} /> - {children}} - > + {item.children.map((child, i) => ( ))} @@ -146,27 +195,25 @@ export const Communities = ({ disabled }: ModalProps) => { return (
- {children}} - > +
) - }) - : null + }), + [communities, form, handleCategoryToggle, selectedChildren, t, wrapInStack] + ) return ( <> handler.close()} - title={} + opened={modalOpen} + onClose={modalHandler.close} + title={} scrollAreaComponent={Modal.NativeScrollArea} > @@ -177,7 +224,7 @@ export const Communities = ({ disabled }: ModalProps) => { {options} - @@ -188,10 +235,13 @@ export const Communities = ({ disabled }: ModalProps) => { diff --git a/packages/ui/icon/iconList.ts b/packages/ui/icon/iconList.ts index 6c8e6f8d18..e81b7ead42 100644 --- a/packages/ui/icon/iconList.ts +++ b/packages/ui/icon/iconList.ts @@ -1,3 +1,3 @@ // generated file - do not modify directly // prettier-ignore -export const iconList = ["carbon:3d-cursor","carbon:3d-cursor-alt","carbon:3d-curve-auto-colon","carbon:3d-curve-auto-vessels","carbon:3d-curve-manual","carbon:3d-ica","carbon:3d-mpr-toggle","carbon:3d-print-mesh","carbon:3d-software","carbon:3rd-party-connected","carbon:4k","carbon:4k-filled","carbon:accessibility","carbon:accessibility-alt","carbon:accessibility-color","carbon:accessibility-color-filled","carbon:account","carbon:accumulation-ice","carbon:accumulation-precipitation","carbon:accumulation-rain","carbon:accumulation-snow","carbon:activity","carbon:add","carbon:add-alt","carbon:add-comment","carbon:add-filled","carbon:add-large","carbon:agriculture-analytics","carbon:ai","carbon:ai-governance-lifecycle","carbon:ai-governance-tracked","carbon:ai-governance-untracked","carbon:ai-launch","carbon:ai-results","carbon:ai-results-high","carbon:ai-results-low","carbon:ai-results-medium","carbon:ai-results-urgent","carbon:ai-results-very-high","carbon:ai-status","carbon:ai-status-complete","carbon:ai-status-failed","carbon:ai-status-in-progress","carbon:ai-status-queued","carbon:ai-status-rejected","carbon:airline-digital-gate","carbon:airline-manage-gates","carbon:airline-passenger-care","carbon:airline-rapid-board","carbon:airplay","carbon:airplay-filled","carbon:airport-01","carbon:airport-02","carbon:airport-location","carbon:alarm","carbon:alarm-add","carbon:alarm-subtract","carbon:align-box-bottom-center","carbon:align-box-bottom-left","carbon:align-box-bottom-right","carbon:align-box-middle-center","carbon:align-box-middle-left","carbon:align-box-middle-right","carbon:align-box-top-center","carbon:align-box-top-left","carbon:align-box-top-right","carbon:align-horizontal-center","carbon:align-horizontal-left","carbon:align-horizontal-right","carbon:align-vertical-bottom","carbon:align-vertical-center","carbon:align-vertical-top","carbon:analytics","carbon:analytics-custom","carbon:analytics-reference","carbon:angle","carbon:annotation-visibility","carbon:aperture","carbon:api","carbon:api-1","carbon:app","carbon:app-connectivity","carbon:app-switcher","carbon:apple","carbon:apple-dash","carbon:application","carbon:application-mobile","carbon:application-virtual","carbon:application-web","carbon:apps","carbon:archive","carbon:area","carbon:area-custom","carbon:arithmetic-mean","carbon:arithmetic-median","carbon:arrival","carbon:arrow-annotation","carbon:arrow-down","carbon:arrow-down-left","carbon:arrow-down-right","carbon:arrow-left","carbon:arrow-right","carbon:arrow-shift-down","carbon:arrow-up","carbon:arrow-up-left","carbon:arrow-up-right","carbon:arrows","carbon:arrows-horizontal","carbon:arrows-vertical","carbon:asleep","carbon:asleep-filled","carbon:assembly","carbon:assembly-cluster","carbon:assembly-reference","carbon:asset","carbon:asset-confirm","carbon:asset-digital-twin","carbon:asset-view","carbon:asterisk","carbon:async","carbon:at","carbon:attachment","carbon:audio-console","carbon:augmented-reality","carbon:auto-scroll","carbon:automatic","carbon:autoscaling","carbon:awake","carbon:back-to-top","carbon:badge","carbon:baggage-claim","carbon:bar","carbon:barcode","carbon:bare-metal-server","carbon:bare-metal-server-01","carbon:bare-metal-server-02","carbon:barrier","carbon:basketball","carbon:bastion-host","carbon:bat","carbon:batch-job","carbon:batch-job-step","carbon:battery-charging","carbon:battery-empty","carbon:battery-full","carbon:battery-half","carbon:battery-low","carbon:battery-quarter","carbon:bee","carbon:bee-bat","carbon:beta","carbon:bicycle","carbon:binoculars","carbon:bloch-sphere","carbon:block-storage","carbon:block-storage-alt","carbon:blockchain","carbon:blog","carbon:bluetooth","carbon:bluetooth-off","carbon:book","carbon:bookmark","carbon:bookmark-add","carbon:bookmark-filled","carbon:boolean","carbon:boot","carbon:boot-volume","carbon:boot-volume-alt","carbon:border-bottom","carbon:border-full","carbon:border-left","carbon:border-none","carbon:border-right","carbon:border-top","carbon:bot","carbon:bottles-01","carbon:bottles-01-dash","carbon:bottles-02","carbon:bottles-02-dash","carbon:bottles-container","carbon:box","carbon:box-extra-large","carbon:box-large","carbon:box-medium","carbon:box-plot","carbon:box-small","carbon:branch","carbon:breaking-change","carbon:brightness-contrast","carbon:bring-forward","carbon:bring-to-front","carbon:brush-freehand","carbon:brush-polygon","carbon:build-tool","carbon:building","carbon:building-insights-1","carbon:building-insights-2","carbon:building-insights-3","carbon:bullhorn","carbon:buoy","carbon:bus","carbon:business-processes","carbon:button-centered","carbon:button-flush-left","carbon:cabin-care","carbon:cabin-care-alert","carbon:cabin-care-alt","carbon:cad","carbon:cafe","carbon:calculation","carbon:calculation-alt","carbon:calculator","carbon:calculator-check","carbon:calendar","carbon:calendar-add","carbon:calendar-add-alt","carbon:calendar-heat-map","carbon:calendar-settings","carbon:calendar-tools","carbon:calibrate","carbon:calls","carbon:calls-all","carbon:calls-incoming","carbon:camera","carbon:camera-action","carbon:campsite","carbon:car","carbon:car-front","carbon:carbon","carbon:carbon-accounting","carbon:carbon-for-ibm-dotcom","carbon:carbon-for-ibm-product","carbon:carbon-for-mobile","carbon:carbon-for-salesforce","carbon:carbon-ui-builder","carbon:caret-down","carbon:caret-left","carbon:caret-right","carbon:caret-sort","carbon:caret-sort-down","carbon:caret-sort-up","carbon:caret-up","carbon:carousel-horizontal","carbon:carousel-vertical","carbon:catalog","carbon:catalog-publish","carbon:categories","carbon:category","carbon:category-add","carbon:category-and","carbon:category-new","carbon:category-new-each","carbon:ccx","carbon:cd-archive","carbon:cd-create-archive","carbon:cd-create-exchange","carbon:cda","carbon:cell-tower","carbon:center-circle","carbon:center-square","carbon:center-to-fit","carbon:certificate","carbon:certificate-check","carbon:change-catalog","carbon:character-decimal","carbon:character-fraction","carbon:character-integer","carbon:character-lower-case","carbon:character-negative-number","carbon:character-patterns","carbon:character-sentence-case","carbon:character-upper-case","carbon:character-whole-number","carbon:charging-station","carbon:charging-station-filled","carbon:chart-3d","carbon:chart-area","carbon:chart-area-smooth","carbon:chart-area-stepper","carbon:chart-average","carbon:chart-bar","carbon:chart-bar-floating","carbon:chart-bar-overlay","carbon:chart-bar-stacked","carbon:chart-bar-target","carbon:chart-bubble","carbon:chart-bubble-packed","carbon:chart-bullet","carbon:chart-candlestick","carbon:chart-cluster-bar","carbon:chart-column","carbon:chart-column-floating","carbon:chart-column-target","carbon:chart-combo","carbon:chart-combo-stacked","carbon:chart-custom","carbon:chart-dual-y-axis","carbon:chart-error-bar","carbon:chart-error-bar-alt","carbon:chart-evaluation","carbon:chart-high-low","carbon:chart-histogram","carbon:chart-line","carbon:chart-line-data","carbon:chart-line-smooth","carbon:chart-logistic-regression","carbon:chart-marimekko","carbon:chart-maximum","carbon:chart-median","carbon:chart-minimum","carbon:chart-multi-line","carbon:chart-multitype","carbon:chart-network","carbon:chart-parallel","carbon:chart-pie","carbon:chart-planning-waterfall","carbon:chart-point","carbon:chart-population","carbon:chart-radar","carbon:chart-radial","carbon:chart-relationship","carbon:chart-ring","carbon:chart-river","carbon:chart-rose","carbon:chart-scatter","carbon:chart-spiral","carbon:chart-stacked","carbon:chart-stepper","carbon:chart-sunburst","carbon:chart-t-sne","carbon:chart-treemap","carbon:chart-venn-diagram","carbon:chart-violin-plot","carbon:chart-waterfall","carbon:chart-win-loss","carbon:chat","carbon:chat-bot","carbon:chat-launch","carbon:chat-off","carbon:chat-operational","carbon:checkbox","carbon:checkbox-checked","carbon:checkbox-checked-filled","carbon:checkbox-indeterminate","carbon:checkbox-indeterminate-filled","carbon:checkbox-undeterminate","carbon:checkbox-undeterminate-filled","carbon:checkmark","carbon:checkmark-filled","carbon:checkmark-filled-error","carbon:checkmark-filled-warning","carbon:checkmark-outline","carbon:checkmark-outline-error","carbon:checkmark-outline-warning","carbon:chemistry","carbon:chemistry-reference","carbon:chevron-down","carbon:chevron-down-outline","carbon:chevron-left","carbon:chevron-mini","carbon:chevron-right","carbon:chevron-sort","carbon:chevron-sort-down","carbon:chevron-sort-up","carbon:chevron-up","carbon:chevron-up-outline","carbon:chip","carbon:choices","carbon:choose-item","carbon:choropleth-map","carbon:cics-cmas","carbon:cics-db2-connection","carbon:cics-explorer","carbon:cics-program","carbon:cics-region","carbon:cics-region-alt","carbon:cics-region-routing","carbon:cics-region-target","carbon:cics-sit","carbon:cics-sit-overrides","carbon:cics-system-group","carbon:cics-transaction-server-zos","carbon:cics-wui-region","carbon:cicsplex","carbon:circle-dash","carbon:circle-filled","carbon:circle-measurement","carbon:circle-packing","carbon:circle-solid","carbon:circuit-composer","carbon:classification","carbon:classifier-language","carbon:clean","carbon:close","carbon:close-filled","carbon:close-large","carbon:close-outline","carbon:closed-caption","carbon:closed-caption-alt","carbon:closed-caption-filled","carbon:cloud","carbon:cloud-alerting","carbon:cloud-app","carbon:cloud-auditing","carbon:cloud-ceiling","carbon:cloud-data-ops","carbon:cloud-download","carbon:cloud-foundry-1","carbon:cloud-foundry-2","carbon:cloud-lightning","carbon:cloud-logging","carbon:cloud-monitoring","carbon:cloud-offline","carbon:cloud-rain","carbon:cloud-registry","carbon:cloud-satellite","carbon:cloud-satellite-config","carbon:cloud-satellite-link","carbon:cloud-satellite-services","carbon:cloud-service-management","carbon:cloud-services","carbon:cloud-snow","carbon:cloud-upload","carbon:cloudy","carbon:cobb-angle","carbon:code","carbon:code-hide","carbon:code-reference","carbon:code-signing-service","carbon:cognitive","carbon:collaborate","carbon:collapse-all","carbon:collapse-categories","carbon:color-palette","carbon:color-switch","carbon:column","carbon:column-delete","carbon:column-dependency","carbon:column-insert","carbon:commit","carbon:communication-unified","carbon:compare","carbon:compass","carbon:composer-edit","carbon:concept","carbon:condition-point","carbon:condition-wait-point","carbon:connect","carbon:connect-recursive","carbon:connect-reference","carbon:connect-source","carbon:connect-target","carbon:connection-receive","carbon:connection-send","carbon:connection-signal","carbon:connection-signal-off","carbon:connection-two-way","carbon:construction","carbon:container-registry","carbon:container-services","carbon:container-software","carbon:content-delivery-network","carbon:content-view","carbon:continue","carbon:continue-filled","carbon:continuous-deployment","carbon:continuous-integration","carbon:contour-draw","carbon:contour-edit","carbon:contour-finding","carbon:contrast","carbon:convert-to-cloud","carbon:cookie","carbon:copy","carbon:copy-file","carbon:copy-link","carbon:corn","carbon:corner","carbon:coronavirus","carbon:cost","carbon:cost-total","carbon:cough","carbon:course","carbon:covariate","carbon:credentials","carbon:crop","carbon:crop-growth","carbon:crop-health","carbon:cross-reference","carbon:cross-tab","carbon:crossroads","carbon:crowd-report","carbon:crowd-report-filled","carbon:csv","carbon:cu1","carbon:cu3","carbon:cube","carbon:cube-view","carbon:currency","carbon:currency-baht","carbon:currency-dollar","carbon:currency-euro","carbon:currency-lira","carbon:currency-pound","carbon:currency-ruble","carbon:currency-rupee","carbon:currency-shekel","carbon:currency-won","carbon:currency-yen","carbon:cursor-1","carbon:cursor-2","carbon:customer","carbon:customer-service","carbon:cut","carbon:cut-in-half","carbon:cut-out","carbon:cy","carbon:cyclist","carbon:cz","carbon:dashboard","carbon:dashboard-reference","carbon:data-1","carbon:data-2","carbon:data-accessor","carbon:data-analytics","carbon:data-backup","carbon:data-base","carbon:data-base-alt","carbon:data-bin","carbon:data-blob","carbon:data-categorical","carbon:data-center","carbon:data-check","carbon:data-class","carbon:data-collection","carbon:data-connected","carbon:data-definition","carbon:data-diode","carbon:data-enrichment","carbon:data-enrichment-add","carbon:data-error","carbon:data-format","carbon:data-player","carbon:data-quality-definition","carbon:data-reference","carbon:data-refinery","carbon:data-refinery-reference","carbon:data-regular","carbon:data-set","carbon:data-share","carbon:data-structured","carbon:data-table","carbon:data-table-reference","carbon:data-unreal","carbon:data-unstructured","carbon:data-view","carbon:data-view-alt","carbon:data-vis-1","carbon:data-vis-2","carbon:data-vis-3","carbon:data-vis-4","carbon:data-volume","carbon:data-volume-alt","carbon:database-datastax","carbon:database-elastic","carbon:database-enterprise-db2","carbon:database-enterprisedb","carbon:database-etcd","carbon:database-messaging","carbon:database-mongodb","carbon:database-postgresql","carbon:database-rabbit","carbon:database-redis","carbon:datastore","carbon:db2-buffer-pool","carbon:db2-data-sharing-group","carbon:db2-database","carbon:debug","carbon:decision-tree","carbon:delete","carbon:delivery","carbon:delivery-add","carbon:delivery-parcel","carbon:delivery-truck","carbon:demo","carbon:denominate","carbon:departure","carbon:deploy","carbon:deploy-rules","carbon:deployment-pattern","carbon:deployment-policy","carbon:deployment-unit-data","carbon:deployment-unit-execution","carbon:deployment-unit-installation","carbon:deployment-unit-presentation","carbon:deployment-unit-technical-data","carbon:deployment-unit-technical-execution","carbon:deployment-unit-technical-installation","carbon:deployment-unit-technical-presentation","carbon:desk-adjustable","carbon:development","carbon:devices","carbon:devices-apps","carbon:dew-point","carbon:dew-point-filled","carbon:diagram","carbon:diagram-reference","carbon:dicom-6000","carbon:dicom-overlay","carbon:direct-link","carbon:direction-bear-right-01","carbon:direction-bear-right-01-filled","carbon:direction-bear-right-02","carbon:direction-bear-right-02-filled","carbon:direction-curve","carbon:direction-curve-filled","carbon:direction-fork","carbon:direction-fork-filled","carbon:direction-loop-left","carbon:direction-loop-left-filled","carbon:direction-loop-right","carbon:direction-loop-right-filled","carbon:direction-merge","carbon:direction-merge-filled","carbon:direction-right-01","carbon:direction-right-01-filled","carbon:direction-right-02","carbon:direction-right-02-filled","carbon:direction-rotary-first-right","carbon:direction-rotary-first-right-filled","carbon:direction-rotary-right","carbon:direction-rotary-right-filled","carbon:direction-rotary-straight","carbon:direction-rotary-straight-filled","carbon:direction-sharp-turn","carbon:direction-sharp-turn-filled","carbon:direction-straight","carbon:direction-straight-filled","carbon:direction-straight-right","carbon:direction-straight-right-filled","carbon:direction-u-turn","carbon:direction-u-turn-filled","carbon:directory-domain","carbon:distribute-horizontal-center","carbon:distribute-horizontal-left","carbon:distribute-horizontal-right","carbon:distribute-vertical-bottom","carbon:distribute-vertical-center","carbon:distribute-vertical-top","carbon:dna","carbon:dns-services","carbon:doc","carbon:document","carbon:document-add","carbon:document-attachment","carbon:document-audio","carbon:document-blank","carbon:document-download","carbon:document-epdf","carbon:document-export","carbon:document-horizontal","carbon:document-import","carbon:document-multiple-01","carbon:document-multiple-02","carbon:document-pdf","carbon:document-preliminary","carbon:document-protected","carbon:document-security","carbon:document-sentiment","carbon:document-signed","carbon:document-sketch","carbon:document-subtract","carbon:document-tasks","carbon:document-unknown","carbon:document-unprotected","carbon:document-vertical","carbon:document-video","carbon:document-view","carbon:document-word-processor","carbon:document-word-processor-reference","carbon:dog-walker","carbon:dot-mark","carbon:double-integer","carbon:down-to-bottom","carbon:download","carbon:download-study","carbon:downstream","carbon:drag-horizontal","carbon:drag-vertical","carbon:draggable","carbon:draw","carbon:drill-back","carbon:drill-down","carbon:drill-through","carbon:drink-01","carbon:drink-02","carbon:driver-analysis","carbon:drone","carbon:drone-delivery","carbon:drone-front","carbon:drone-video","carbon:drop-photo","carbon:drop-photo-filled","carbon:drought","carbon:dvr","carbon:earth","carbon:earth-americas","carbon:earth-americas-filled","carbon:earth-europe-africa","carbon:earth-europe-africa-filled","carbon:earth-filled","carbon:earth-southeast-asia","carbon:earth-southeast-asia-filled","carbon:earthquake","carbon:edge-cluster","carbon:edge-device","carbon:edge-enhancement","carbon:edge-enhancement-01","carbon:edge-enhancement-02","carbon:edge-enhancement-03","carbon:edge-node","carbon:edge-node-alt","carbon:edge-service","carbon:edit","carbon:edit-filter","carbon:edit-off","carbon:edt-loop","carbon:education","carbon:email","carbon:email-new","carbon:encryption","carbon:energy-renewable","carbon:enterprise","carbon:equal-approximately","carbon:equalizer","carbon:erase","carbon:erase-3d","carbon:error","carbon:error-filled","carbon:error-outline","carbon:event","carbon:event-change","carbon:event-incident","carbon:event-schedule","carbon:event-warning","carbon:events","carbon:events-alt","carbon:exam-mode","carbon:executable-program","carbon:exit","carbon:expand-all","carbon:expand-categories","carbon:explore","carbon:export","carbon:eyedropper","carbon:face-activated","carbon:face-activated-add","carbon:face-activated-filled","carbon:face-add","carbon:face-cool","carbon:face-dissatisfied","carbon:face-dissatisfied-filled","carbon:face-dizzy","carbon:face-dizzy-filled","carbon:face-mask","carbon:face-neutral","carbon:face-neutral-filled","carbon:face-pending","carbon:face-pending-filled","carbon:face-satisfied","carbon:face-satisfied-filled","carbon:face-wink","carbon:face-wink-filled","carbon:factor","carbon:fade","carbon:favorite","carbon:favorite-filled","carbon:favorite-half","carbon:fetch-upload","carbon:fetch-upload-cloud","carbon:file-storage","carbon:filter","carbon:filter-edit","carbon:filter-remove","carbon:filter-reset","carbon:finance","carbon:fingerprint-recognition","carbon:fire","carbon:firewall","carbon:firewall-classic","carbon:fish","carbon:fish-multiple","carbon:fit-to-height","carbon:fit-to-screen","carbon:fit-to-width","carbon:flag","carbon:flag-filled","carbon:flagging-taxi","carbon:flash","carbon:flash-filled","carbon:flash-off","carbon:flash-off-filled","carbon:flight-international","carbon:flight-roster","carbon:flight-schedule","carbon:floating-ip","carbon:flood","carbon:flood-warning","carbon:floorplan","carbon:flow","carbon:flow-connection","carbon:flow-data","carbon:flow-logs-vpc","carbon:flow-modeler","carbon:flow-modeler-reference","carbon:flow-stream","carbon:flow-stream-reference","carbon:fog","carbon:folder","carbon:folder-add","carbon:folder-details","carbon:folder-details-reference","carbon:folder-move-to","carbon:folder-off","carbon:folder-open","carbon:folder-parent","carbon:folder-shared","carbon:folders","carbon:forecast-hail","carbon:forecast-hail-30","carbon:forecast-lightning","carbon:forecast-lightning-30","carbon:fork","carbon:forum","carbon:forward-10","carbon:forward-30","carbon:forward-5","carbon:foundation-model","carbon:fragile","carbon:friendship","carbon:fruit-bowl","carbon:function","carbon:function-math","carbon:fusion-blender","carbon:game-console","carbon:game-wireless","carbon:gamification","carbon:gas-station","carbon:gas-station-filled","carbon:gateway","carbon:gateway-api","carbon:gateway-mail","carbon:gateway-public","carbon:gateway-security","carbon:gateway-user-access","carbon:gateway-vpn","carbon:gender-female","carbon:gender-male","carbon:generate-pdf","carbon:gif","carbon:gift","carbon:global-loan-and-trial","carbon:globe","carbon:gradient","carbon:graphical-data-flow","carbon:grid","carbon:group","carbon:group-access","carbon:group-account","carbon:group-objects","carbon:group-objects-new","carbon:group-objects-save","carbon:group-presentation","carbon:group-resource","carbon:group-security","carbon:growth","carbon:gui","carbon:gui-management","carbon:h","carbon:hail","carbon:hanging-protocol","carbon:harbor","carbon:hardware-security-module","carbon:hashtag","carbon:haze","carbon:haze-night","carbon:hd","carbon:hd-filled","carbon:hdr","carbon:headphones","carbon:headset","carbon:health-cross","carbon:hearing","carbon:heat-map","carbon:heat-map-02","carbon:heat-map-03","carbon:heat-map-stocks","carbon:helicopter","carbon:help","carbon:help-desk","carbon:help-filled","carbon:hinton-plot","carbon:hl7-attributes","carbon:hole-filling","carbon:hole-filling-cursor","carbon:home","carbon:horizontal-view","carbon:hospital","carbon:hospital-bed","carbon:hotel","carbon:hourglass","carbon:html","carbon:html-reference","carbon:http","carbon:humidity","carbon:humidity-alt","carbon:hurricane","carbon:hybrid-networking","carbon:hybrid-networking-alt","carbon:ibm-ai-on-z","carbon:ibm-aiops-insights","carbon:ibm-bluepay","carbon:ibm-cloud","carbon:ibm-cloud-app-id","carbon:ibm-cloud-bare-metal-server","carbon:ibm-cloud-bare-metal-servers-vpc","carbon:ibm-cloud-citrix-daas","carbon:ibm-cloud-continuous-delivery","carbon:ibm-cloud-dedicated-host","carbon:ibm-cloud-direct-link-1-connect","carbon:ibm-cloud-direct-link-1-dedicated","carbon:ibm-cloud-direct-link-1-dedicated-hosting","carbon:ibm-cloud-direct-link-1-exchange","carbon:ibm-cloud-direct-link-2-connect","carbon:ibm-cloud-direct-link-2-dedicated","carbon:ibm-cloud-direct-link-2-dedicated-hosting","carbon:ibm-cloud-event-notification","carbon:ibm-cloud-event-streams","carbon:ibm-cloud-for-education","carbon:ibm-cloud-hpc","carbon:ibm-cloud-hsm","carbon:ibm-cloud-hyper-protect-crypto-services","carbon:ibm-cloud-hyper-protect-dbaas","carbon:ibm-cloud-hyper-protect-vs","carbon:ibm-cloud-internet-services","carbon:ibm-cloud-ipsec-vpn","carbon:ibm-cloud-key-protect","carbon:ibm-cloud-kubernetes-service","carbon:ibm-cloud-logging","carbon:ibm-cloud-mass-data-migration","carbon:ibm-cloud-pak-applications","carbon:ibm-cloud-pak-business-automation","carbon:ibm-cloud-pak-data","carbon:ibm-cloud-pak-integration","carbon:ibm-cloud-pak-manta-automated-data-lineage","carbon:ibm-cloud-pak-multicloud-mgmt","carbon:ibm-cloud-pak-netezza","carbon:ibm-cloud-pak-network-automation","carbon:ibm-cloud-pak-security","carbon:ibm-cloud-pak-system","carbon:ibm-cloud-pak-watson-aiops","carbon:ibm-cloud-pal","carbon:ibm-cloud-privileged-access-gateway","carbon:ibm-cloud-projects","carbon:ibm-cloud-resiliency","carbon:ibm-cloud-secrets-manager","carbon:ibm-cloud-security-compliance-center","carbon:ibm-cloud-security-compliance-center-workload-protection","carbon:ibm-cloud-subnets","carbon:ibm-cloud-sysdig-secure","carbon:ibm-cloud-transit-gateway","carbon:ibm-cloud-virtual-server-classic","carbon:ibm-cloud-virtual-server-vpc","carbon:ibm-cloud-vpc","carbon:ibm-cloud-vpc-endpoints","carbon:ibm-cloudant","carbon:ibm-content-services","carbon:ibm-data-product-exchange","carbon:ibm-data-replication","carbon:ibm-datastage","carbon:ibm-db2","carbon:ibm-db2-alt","carbon:ibm-db2-warehouse","carbon:ibm-dynamic-route-server","carbon:ibm-engineering-systems-design-rhapsody-model-manager","carbon:ibm-engineering-systems-design-rhapsody-sn1","carbon:ibm-engineering-systems-design-rhapsody-sn2","carbon:ibm-event-automation","carbon:ibm-event-endpoint-mgmt","carbon:ibm-event-processing","carbon:ibm-event-streams","carbon:ibm-ibv","carbon:ibm-instana","carbon:ibm-match-360","carbon:ibm-mq","carbon:ibm-open-enterprise-languages","carbon:ibm-openshift-container-platform-on-vpc-for-regulated-industries","carbon:ibm-power-vs","carbon:ibm-power-vs-private-cloud","carbon:ibm-power-with-vpc","carbon:ibm-private-path-services","carbon:ibm-process-mining","carbon:ibm-saas-console","carbon:ibm-sap-on-power","carbon:ibm-secure-infrastructure-on-vpc-for-regulated-industries","carbon:ibm-security","carbon:ibm-security-services","carbon:ibm-telehealth","carbon:ibm-tenet","carbon:ibm-toolchain","carbon:ibm-turbonomic","carbon:ibm-vpn-for-vpc","carbon:ibm-vsi-on-vpc-for-regulated-industries","carbon:ibm-watson-assistant","carbon:ibm-watson-discovery","carbon:ibm-watson-knowledge-catalog","carbon:ibm-watson-knowledge-studio","carbon:ibm-watson-language-translator","carbon:ibm-watson-machine-learning","carbon:ibm-watson-natural-language-classifier","carbon:ibm-watson-natural-language-understanding","carbon:ibm-watson-openscale","carbon:ibm-watson-orders","carbon:ibm-watson-query","carbon:ibm-watson-speech-to-text","carbon:ibm-watson-studio","carbon:ibm-watson-text-to-speech","carbon:ibm-watson-tone-analyzer","carbon:ibm-watsonx-assistant","carbon:ibm-watsonx-code-assistant","carbon:ibm-watsonx-code-assistant-for-z","carbon:ibm-watsonx-code-assistant-for-z-refactor","carbon:ibm-watsonx-orchestrate","carbon:ibm-wazi-deploy","carbon:ibm-z-cloud-mod-stack","carbon:ibm-z-cloud-provisioning","carbon:ibm-z-environments-dev-sec-ops","carbon:ibm-z-os","carbon:ibm-z-os-ai-control-interface","carbon:ibm-z-os-containers","carbon:ibm-z-os-package-manager","carbon:ibm-z-processor-capacity-reference","carbon:ica-2d","carbon:ice-accretion","carbon:ice-vision","carbon:id","carbon:id-management","carbon:idea","carbon:identification","carbon:image","carbon:image-copy","carbon:image-medical","carbon:image-reference","carbon:image-search","carbon:image-search-alt","carbon:image-service","carbon:import-export","carbon:improve-relevance","carbon:in-progress","carbon:in-progress-error","carbon:in-progress-warning","carbon:incomplete","carbon:incomplete-cancel","carbon:incomplete-error","carbon:incomplete-warning","carbon:increase-level","carbon:industry","carbon:infinity","carbon:infinity-symbol","carbon:information","carbon:information-disabled","carbon:information-filled","carbon:information-square","carbon:information-square-filled","carbon:infrastructure-classic","carbon:insert","carbon:insert-page","carbon:insert-syntax","carbon:inspection","carbon:instance-bx","carbon:instance-classic","carbon:instance-cx","carbon:instance-mx","carbon:instance-virtual","carbon:integration","carbon:intent-request-active","carbon:intent-request-create","carbon:intent-request-heal","carbon:intent-request-inactive","carbon:intent-request-scale-in","carbon:intent-request-scale-out","carbon:intent-request-uninstall","carbon:intent-request-upgrade","carbon:interactions","carbon:interactive-segmentation-cursor","carbon:intersect","carbon:intrusion-prevention","carbon:inventory-management","carbon:iot-connect","carbon:iot-platform","carbon:ip","carbon:iso","carbon:iso-filled","carbon:iso-outline","carbon:join-full","carbon:join-inner","carbon:join-left","carbon:join-outer","carbon:join-right","carbon:jpg","carbon:js-error","carbon:json","carbon:json-reference","carbon:jump-link","carbon:keep-dry","carbon:keyboard","carbon:keyboard-off","carbon:kubernetes","carbon:kubernetes-ip-address","carbon:kubernetes-pod","carbon:label","carbon:language","carbon:laptop","carbon:lasso","carbon:lasso-polygon","carbon:launch","carbon:launch-study-1","carbon:launch-study-2","carbon:launch-study-3","carbon:layers","carbon:legend","carbon:letter-aa","carbon:letter-aa-large","carbon:letter-bb","carbon:letter-cc","carbon:letter-dd","carbon:letter-ee","carbon:letter-ff","carbon:letter-gg","carbon:letter-hh","carbon:letter-ii","carbon:letter-jj","carbon:letter-kk","carbon:letter-ll","carbon:letter-mm","carbon:letter-nn","carbon:letter-oo","carbon:letter-pp","carbon:letter-qq","carbon:letter-rr","carbon:letter-ss","carbon:letter-tt","carbon:letter-uu","carbon:letter-vv","carbon:letter-ww","carbon:letter-xx","carbon:letter-yy","carbon:letter-zz","carbon:license","carbon:license-draft","carbon:license-global","carbon:license-maintenance","carbon:license-maintenance-draft","carbon:license-third-party","carbon:license-third-party-draft","carbon:lifesaver","carbon:light","carbon:light-filled","carbon:lightning","carbon:link","carbon:linux","carbon:linux-alt","carbon:list","carbon:list-boxes","carbon:list-bulleted","carbon:list-checked","carbon:list-checked-mirror","carbon:list-dropdown","carbon:list-numbered","carbon:list-numbered-mirror","carbon:load-balancer-application","carbon:load-balancer-classic","carbon:load-balancer-global","carbon:load-balancer-listener","carbon:load-balancer-local","carbon:load-balancer-network","carbon:load-balancer-pool","carbon:load-balancer-vpc","carbon:location","carbon:location-company","carbon:location-company-filled","carbon:location-current","carbon:location-filled","carbon:location-hazard","carbon:location-hazard-filled","carbon:location-heart","carbon:location-heart-filled","carbon:location-person","carbon:location-person-filled","carbon:location-save","carbon:location-star","carbon:location-star-filled","carbon:locked","carbon:logical-partition","carbon:login","carbon:logo-angular","carbon:logo-ansible-community","carbon:logo-delicious","carbon:logo-digg","carbon:logo-discord","carbon:logo-facebook","carbon:logo-figma","carbon:logo-flickr","carbon:logo-github","carbon:logo-gitlab","carbon:logo-glassdoor","carbon:logo-google","carbon:logo-instagram","carbon:logo-invision","carbon:logo-jupyter","carbon:logo-keybase","carbon:logo-kubernetes","carbon:logo-linkedin","carbon:logo-livestream","carbon:logo-mastodon","carbon:logo-medium","carbon:logo-npm","carbon:logo-openshift","carbon:logo-pinterest","carbon:logo-python","carbon:logo-quora","carbon:logo-r-script","carbon:logo-react","carbon:logo-red-hat-ansible","carbon:logo-sketch","carbon:logo-skype","carbon:logo-slack","carbon:logo-snapchat","carbon:logo-stumbleupon","carbon:logo-svelte","carbon:logo-tumblr","carbon:logo-twitter","carbon:logo-vmware","carbon:logo-vmware-alt","carbon:logo-vue","carbon:logo-wechat","carbon:logo-x","carbon:logo-xing","carbon:logo-yelp","carbon:logo-youtube","carbon:logout","carbon:loop","carbon:mac","carbon:mac-command","carbon:mac-option","carbon:mac-shift","carbon:machine-learning","carbon:machine-learning-model","carbon:magic-wand","carbon:magic-wand-filled","carbon:magnify","carbon:mail-all","carbon:mail-reply","carbon:mammogram","carbon:mammogram-stacked","carbon:manage-protection","carbon:managed-solutions","carbon:map","carbon:map-boundary","carbon:map-boundary-vegetation","carbon:map-center","carbon:map-identify","carbon:marine-warning","carbon:math-curve","carbon:matrix","carbon:maximize","carbon:media-cast","carbon:media-library","carbon:media-library-filled","carbon:medication","carbon:medication-alert","carbon:medication-reminder","carbon:menu","carbon:message-queue","carbon:meter","carbon:meter-alt","carbon:microphone","carbon:microphone-filled","carbon:microphone-off","carbon:microphone-off-filled","carbon:microscope","carbon:microservices-1","carbon:microservices-2","carbon:migrate","carbon:migrate-alt","carbon:milestone","carbon:military-camp","carbon:minimize","carbon:misuse","carbon:misuse-alt","carbon:misuse-outline","carbon:mixed-rain-hail","carbon:mobile","carbon:mobile-add","carbon:mobile-audio","carbon:mobile-check","carbon:mobile-crash","carbon:mobile-download","carbon:mobile-event","carbon:mobile-landscape","carbon:mobile-request","carbon:mobile-session","carbon:mobile-view","carbon:mobile-view-orientation","carbon:mobility-services","carbon:model","carbon:model-alt","carbon:model-builder","carbon:model-builder-reference","carbon:model-reference","carbon:model-tuned","carbon:money","carbon:monster","carbon:monument","carbon:moon","carbon:moonrise","carbon:moonset","carbon:mostly-cloudy","carbon:mostly-cloudy-night","carbon:mountain","carbon:mov","carbon:move","carbon:movement","carbon:mp3","carbon:mp4","carbon:mpeg","carbon:mpg2","carbon:music","carbon:music-add","carbon:music-remove","carbon:mysql","carbon:name-space","carbon:navaid-civil","carbon:navaid-dme","carbon:navaid-helipad","carbon:navaid-military","carbon:navaid-military-civil","carbon:navaid-ndb","carbon:navaid-ndb-dme","carbon:navaid-private","carbon:navaid-seaplane","carbon:navaid-tacan","carbon:navaid-vhfor","carbon:navaid-vor","carbon:navaid-vordme","carbon:navaid-vortac","carbon:need","carbon:network-1","carbon:network-2","carbon:network-3","carbon:network-3-reference","carbon:network-4","carbon:network-4-reference","carbon:network-admin-control","carbon:network-enterprise","carbon:network-interface","carbon:network-overlay","carbon:network-public","carbon:new-tab","carbon:next-filled","carbon:next-outline","carbon:no-image","carbon:no-ticket","carbon:nominal","carbon:nominate","carbon:non-certified","carbon:noodle-bowl","carbon:not-available","carbon:not-sent","carbon:not-sent-filled","carbon:notebook","carbon:notebook-reference","carbon:notification","carbon:notification-filled","carbon:notification-new","carbon:notification-off","carbon:notification-off-filled","carbon:number-0","carbon:number-1","carbon:number-2","carbon:number-3","carbon:number-4","carbon:number-5","carbon:number-6","carbon:number-7","carbon:number-8","carbon:number-9","carbon:number-small-0","carbon:number-small-1","carbon:number-small-2","carbon:number-small-3","carbon:number-small-4","carbon:number-small-5","carbon:number-small-6","carbon:number-small-7","carbon:number-small-8","carbon:number-small-9","carbon:object-storage","carbon:object-storage-alt","carbon:observed-hail","carbon:observed-lightning","carbon:omega","carbon:opacity","carbon:open-panel-bottom","carbon:open-panel-filled-bottom","carbon:open-panel-filled-left","carbon:open-panel-filled-right","carbon:open-panel-filled-top","carbon:open-panel-left","carbon:open-panel-right","carbon:open-panel-top","carbon:operation","carbon:operation-gauge","carbon:operation-if","carbon:operations-field","carbon:operations-record","carbon:order-details","carbon:ordinal","carbon:outage","carbon:outlook-severe","carbon:overflow-menu-horizontal","carbon:overflow-menu-vertical","carbon:overlay","carbon:package","carbon:package-text-analysis","carbon:page-break","carbon:page-first","carbon:page-last","carbon:page-number","carbon:page-scroll","carbon:paint-brush","carbon:paint-brush-alt","carbon:palm-tree","carbon:pan-horizontal","carbon:pan-vertical","carbon:panel-expansion","carbon:paragraph","carbon:parameter","carbon:parent-child","carbon:partition-auto","carbon:partition-collection","carbon:partition-repartition","carbon:partition-same","carbon:partition-specific","carbon:partly-cloudy","carbon:partly-cloudy-night","carbon:partnership","carbon:passenger-drinks","carbon:passenger-plus","carbon:password","carbon:paste","carbon:pause","carbon:pause-filled","carbon:pause-future","carbon:pause-outline","carbon:pause-outline-filled","carbon:pause-past","carbon:pcn-e-node","carbon:pcn-military","carbon:pcn-p-node","carbon:pcn-z-node","carbon:pdf","carbon:pdf-reference","carbon:pedestrian","carbon:pedestrian-child","carbon:pedestrian-family","carbon:pen","carbon:pen-fountain","carbon:pending","carbon:pending-filled","carbon:percentage","carbon:percentage-filled","carbon:person","carbon:person-favorite","carbon:pest","carbon:pet-image-b","carbon:pet-image-o","carbon:phone","carbon:phone-application","carbon:phone-block","carbon:phone-block-filled","carbon:phone-filled","carbon:phone-incoming","carbon:phone-incoming-filled","carbon:phone-ip","carbon:phone-off","carbon:phone-off-filled","carbon:phone-outgoing","carbon:phone-outgoing-filled","carbon:phone-settings","carbon:phone-voice","carbon:phone-voice-filled","carbon:phrase-sentiment","carbon:picnic-area","carbon:piggy-bank","carbon:piggy-bank-slot","carbon:pills","carbon:pills-add","carbon:pills-subtract","carbon:pin","carbon:pin-filled","carbon:plan","carbon:plane","carbon:plane-private","carbon:plane-sea","carbon:platforms","carbon:play","carbon:play-filled","carbon:play-filled-alt","carbon:play-outline","carbon:play-outline-filled","carbon:playlist","carbon:plug","carbon:plug-filled","carbon:png","carbon:point-of-presence","carbon:pointer-text","carbon:police","carbon:policy","carbon:popup","carbon:port-input","carbon:port-output","carbon:portfolio","carbon:power","carbon:ppt","carbon:presentation-file","carbon:pressure","carbon:pressure-filled","carbon:previous-filled","carbon:previous-outline","carbon:printer","carbon:process","carbon:process-automate","carbon:product","carbon:progress-bar","carbon:progress-bar-round","carbon:promote","carbon:prompt-session","carbon:prompt-template","carbon:property-relationship","carbon:purchase","carbon:qc-launch","carbon:qq-plot","carbon:qr-code","carbon:quadrant-plot","carbon:query","carbon:query-queue","carbon:queued","carbon:quotes","carbon:radar","carbon:radar-enhanced","carbon:radar-weather","carbon:radio","carbon:radio-button","carbon:radio-button-checked","carbon:radio-combat","carbon:radio-push-to-talk","carbon:rain","carbon:rain-drizzle","carbon:rain-drop","carbon:rain-heavy","carbon:rain-scattered","carbon:rain-scattered-night","carbon:raw","carbon:receipt","carbon:recently-viewed","carbon:recommend","carbon:recording","carbon:recording-filled","carbon:recording-filled-alt","carbon:recycle","carbon:redo","carbon:ref-evapotranspiration","carbon:reference-architecture","carbon:reflect-horizontal","carbon:reflect-vertical","carbon:region-analysis-area","carbon:region-analysis-volume","carbon:registration","carbon:reminder","carbon:reminder-medical","carbon:renew","carbon:repeat","carbon:repeat-one","carbon:replicate","carbon:reply","carbon:reply-all","carbon:repo-artifact","carbon:repo-source-code","carbon:report","carbon:report-data","carbon:request-quote","carbon:research-bloch-sphere","carbon:research-hinton-plot","carbon:research-matrix","carbon:reset","carbon:reset-alt","carbon:restart","carbon:restaurant","carbon:restaurant-fine","carbon:result","carbon:result-draft","carbon:result-new","carbon:result-old","carbon:retry-failed","carbon:return","carbon:review","carbon:rewind-10","carbon:rewind-30","carbon:rewind-5","carbon:right-panel-close","carbon:right-panel-close-filled","carbon:right-panel-open","carbon:right-panel-open-filled","carbon:road","carbon:road-weather","carbon:roadmap","carbon:rocket","carbon:rotate","carbon:rotate-180","carbon:rotate-360","carbon:rotate-clockwise","carbon:rotate-clockwise-alt","carbon:rotate-clockwise-alt-filled","carbon:rotate-clockwise-filled","carbon:rotate-counterclockwise","carbon:rotate-counterclockwise-alt","carbon:rotate-counterclockwise-alt-filled","carbon:rotate-counterclockwise-filled","carbon:router","carbon:router-voice","carbon:router-wifi","carbon:row","carbon:row-collapse","carbon:row-delete","carbon:row-expand","carbon:row-insert","carbon:rss","carbon:rule","carbon:rule-cancelled","carbon:rule-data-quality","carbon:rule-draft","carbon:rule-filled","carbon:rule-locked","carbon:rule-partial","carbon:rule-test","carbon:ruler","carbon:ruler-alt","carbon:run","carbon:run-mirror","carbon:running","carbon:s","carbon:s-alt","carbon:sailboat-coastal","carbon:sailboat-offshore","carbon:sales-ops","carbon:sankey-diagram","carbon:sankey-diagram-alt","carbon:satellite","carbon:satellite-radar","carbon:satellite-weather","carbon:save","carbon:save-annotation","carbon:save-image","carbon:save-model","carbon:save-series","carbon:scale","carbon:scales","carbon:scales-tipped","carbon:scalpel","carbon:scalpel-cursor","carbon:scalpel-lasso","carbon:scalpel-select","carbon:scan","carbon:scan-alt","carbon:scan-disabled","carbon:scatter-matrix","carbon:schematics","carbon:scis-control-tower","carbon:scis-transparent-supply","carbon:scooter","carbon:scooter-front","carbon:screen","carbon:screen-map","carbon:screen-map-set","carbon:screen-off","carbon:script","carbon:script-reference","carbon:sdk","carbon:search","carbon:search-advanced","carbon:search-locate","carbon:search-locate-mirror","carbon:security","carbon:security-services","carbon:select-01","carbon:select-02","carbon:select-window","carbon:send","carbon:send-alt","carbon:send-alt-filled","carbon:send-backward","carbon:send-filled","carbon:send-to-back","carbon:server-dns","carbon:server-proxy","carbon:server-time","carbon:service-desk","carbon:service-id","carbon:service-levels","carbon:session-border-control","carbon:settings","carbon:settings-adjust","carbon:settings-check","carbon:settings-edit","carbon:settings-services","carbon:settings-view","carbon:shape-except","carbon:shape-exclude","carbon:shape-intersect","carbon:shape-join","carbon:shape-unite","carbon:share","carbon:share-knowledge","carbon:shopping-bag","carbon:shopping-cart","carbon:shopping-cart-arrow-down","carbon:shopping-cart-arrow-up","carbon:shopping-cart-clear","carbon:shopping-cart-error","carbon:shopping-cart-minus","carbon:shopping-cart-plus","carbon:shopping-catalog","carbon:show-data-cards","carbon:shrink-screen","carbon:shrink-screen-filled","carbon:shuffle","carbon:shuttle","carbon:side-panel-close","carbon:side-panel-close-filled","carbon:side-panel-open","carbon:side-panel-open-filled","carbon:sight","carbon:sigma","carbon:signal-strength","carbon:sim-card","carbon:skill-level","carbon:skill-level-advanced","carbon:skill-level-basic","carbon:skill-level-intermediate","carbon:skip-back","carbon:skip-back-filled","carbon:skip-back-outline","carbon:skip-back-outline-filled","carbon:skip-back-outline-solid","carbon:skip-back-solid-filled","carbon:skip-forward","carbon:skip-forward-filled","carbon:skip-forward-outline","carbon:skip-forward-outline-filled","carbon:skip-forward-outline-solid","carbon:skip-forward-solid-filled","carbon:sleet","carbon:slisor","carbon:slm","carbon:smell","carbon:smoke","carbon:smoothing","carbon:smoothing-cursor","carbon:snooze","carbon:snow","carbon:snow-blizzard","carbon:snow-density","carbon:snow-heavy","carbon:snow-scattered","carbon:snow-scattered-night","carbon:snowflake","carbon:soccer","carbon:software-resource","carbon:software-resource-cluster","carbon:software-resource-resource","carbon:soil-moisture","carbon:soil-moisture-field","carbon:soil-moisture-global","carbon:soil-temperature","carbon:soil-temperature-field","carbon:soil-temperature-global","carbon:solar-panel","carbon:sort-ascending","carbon:sort-descending","carbon:sort-remove","carbon:spell-check","carbon:spine-label","carbon:split","carbon:split-discard","carbon:split-screen","carbon:spray-paint","carbon:sprout","carbon:sql","carbon:stack-limitation","carbon:stacked-move","carbon:stacked-scrolling-1","carbon:stacked-scrolling-2","carbon:stamp","carbon:star","carbon:star-filled","carbon:star-half","carbon:star-review","carbon:status-acknowledge","carbon:status-change","carbon:status-partial-fail","carbon:status-resolved","carbon:stay-inside","carbon:stem-leaf-plot","carbon:stethoscope","carbon:stop","carbon:stop-filled","carbon:stop-filled-alt","carbon:stop-outline","carbon:stop-outline-filled","carbon:stop-sign","carbon:stop-sign-filled","carbon:storage-pool","carbon:storage-request","carbon:store","carbon:storm-tracker","carbon:strawberry","carbon:stress-breath-editor","carbon:string-integer","carbon:string-text","carbon:study-next","carbon:study-previous","carbon:study-read","carbon:study-skip","carbon:study-transfer","carbon:study-unread","carbon:study-view","carbon:sub-volume","carbon:subdirectory","carbon:subflow","carbon:subflow-local","carbon:subnet-acl-rules","carbon:subtract","carbon:subtract-alt","carbon:subtract-filled","carbon:subtract-large","carbon:summary-kpi","carbon:summary-kpi-mirror","carbon:sun","carbon:sunny","carbon:sunrise","carbon:sunset","carbon:support-vector-machine","carbon:sustainability","carbon:svg","carbon:swim","carbon:switch-layer-2","carbon:switch-layer-3","carbon:switcher","carbon:sync-settings","carbon:sys-provision","carbon:t","carbon:t-alt","carbon:table","carbon:table-alias","carbon:table-built","carbon:table-of-contents","carbon:table-shortcut","carbon:table-split","carbon:tablet","carbon:tablet-landscape","carbon:tag","carbon:tag-edit","carbon:tag-export","carbon:tag-group","carbon:tag-import","carbon:tag-none","carbon:tank","carbon:task","carbon:task-add","carbon:task-approved","carbon:task-asset-view","carbon:task-complete","carbon:task-location","carbon:task-remove","carbon:task-settings","carbon:task-star","carbon:task-tools","carbon:task-view","carbon:taste","carbon:taxi","carbon:tcp-ip-service","carbon:temperature","carbon:temperature-celsius","carbon:temperature-celsius-alt","carbon:temperature-fahrenheit","carbon:temperature-fahrenheit-alt","carbon:temperature-feels-like","carbon:temperature-frigid","carbon:temperature-hot","carbon:temperature-inversion","carbon:temperature-max","carbon:temperature-min","carbon:temperature-water","carbon:template","carbon:tennis","carbon:tennis-ball","carbon:term","carbon:terminal","carbon:terminal-3270","carbon:test-tool","carbon:text-align-center","carbon:text-align-justify","carbon:text-align-left","carbon:text-align-mixed","carbon:text-align-right","carbon:text-all-caps","carbon:text-annotation-toggle","carbon:text-bold","carbon:text-clear-format","carbon:text-color","carbon:text-creation","carbon:text-fill","carbon:text-font","carbon:text-footnote","carbon:text-highlight","carbon:text-indent","carbon:text-indent-less","carbon:text-indent-more","carbon:text-italic","carbon:text-kerning","carbon:text-leading","carbon:text-line-spacing","carbon:text-link","carbon:text-link-analysis","carbon:text-long-paragraph","carbon:text-mining","carbon:text-mining-applier","carbon:text-new-line","carbon:text-scale","carbon:text-selection","carbon:text-short-paragraph","carbon:text-small-caps","carbon:text-strikethrough","carbon:text-subscript","carbon:text-superscript","carbon:text-tracking","carbon:text-underline","carbon:text-vertical-alignment","carbon:text-wrap","carbon:theater","carbon:this-side-up","carbon:threshold","carbon:thumbnail-1","carbon:thumbnail-2","carbon:thumbnail-preview","carbon:thumbs-down","carbon:thumbs-down-filled","carbon:thumbs-up","carbon:thumbs-up-filled","carbon:thunderstorm","carbon:thunderstorm-scattered","carbon:thunderstorm-scattered-night","carbon:thunderstorm-severe","carbon:thunderstorm-strong","carbon:ticket","carbon:tides","carbon:tif","carbon:time","carbon:time-filled","carbon:time-plot","carbon:timer","carbon:tool-box","carbon:tool-kit","carbon:tools","carbon:tools-alt","carbon:tornado","carbon:tornado-warning","carbon:touch-1","carbon:touch-1-down","carbon:touch-1-down-filled","carbon:touch-1-filled","carbon:touch-2","carbon:touch-2-filled","carbon:touch-interaction","carbon:tour","carbon:traffic-cone","carbon:traffic-event","carbon:traffic-flow","carbon:traffic-flow-incident","carbon:traffic-incident","carbon:traffic-weather-incident","carbon:train","carbon:train-heart","carbon:train-profile","carbon:train-speed","carbon:train-ticket","carbon:train-time","carbon:tram","carbon:transform-binary","carbon:transform-instructions","carbon:transform-language","carbon:transgender","carbon:translate","carbon:transmission-lte","carbon:transpose","carbon:trash-can","carbon:tree","carbon:tree-fall-risk","carbon:tree-view","carbon:tree-view-alt","carbon:trophy","carbon:trophy-filled","carbon:tropical-storm","carbon:tropical-storm-model-tracks","carbon:tropical-storm-tracks","carbon:tropical-warning","carbon:tsq","carbon:tsunami","carbon:tsv","carbon:tuning","carbon:two-factor-authentication","carbon:two-person-lift","carbon:txt","carbon:txt-reference","carbon:type-pattern","carbon:types","carbon:u1","carbon:u2","carbon:u3","carbon:umbrella","carbon:undefined","carbon:undefined-filled","carbon:undo","carbon:ungroup-objects","carbon:unknown","carbon:unknown-filled","carbon:unlink","carbon:unlocked","carbon:unsaved","carbon:up-to-top","carbon:update-now","carbon:upgrade","carbon:upload","carbon:upstream","carbon:url","carbon:usb","carbon:user","carbon:user-access","carbon:user-activity","carbon:user-admin","carbon:user-avatar","carbon:user-avatar-filled","carbon:user-avatar-filled-alt","carbon:user-certification","carbon:user-data","carbon:user-favorite","carbon:user-favorite-alt","carbon:user-favorite-alt-filled","carbon:user-filled","carbon:user-follow","carbon:user-identification","carbon:user-military","carbon:user-multiple","carbon:user-online","carbon:user-profile","carbon:user-profile-alt","carbon:user-role","carbon:user-service-desk","carbon:user-settings","carbon:user-simulation","carbon:user-speaker","carbon:user-sponsor","carbon:user-x-ray","carbon:uv-index","carbon:uv-index-alt","carbon:uv-index-filled","carbon:value-variable","carbon:van","carbon:vegetation-asset","carbon:vegetation-encroachment","carbon:vegetation-height","carbon:vehicle-api","carbon:vehicle-connected","carbon:vehicle-insights","carbon:vehicle-services","carbon:version","carbon:version-major","carbon:version-minor","carbon:version-patch","carbon:vertical-view","carbon:video","carbon:video-add","carbon:video-chat","carbon:video-filled","carbon:video-off","carbon:video-off-filled","carbon:video-player","carbon:view","carbon:view-filled","carbon:view-mode-1","carbon:view-mode-2","carbon:view-next","carbon:view-off","carbon:view-off-filled","carbon:virtual-column","carbon:virtual-column-key","carbon:virtual-desktop","carbon:virtual-machine","carbon:virtual-private-cloud","carbon:virtual-private-cloud-alt","carbon:visual-recognition","carbon:vlan","carbon:vlan-ibm","carbon:vmdk-disk","carbon:voice-activate","carbon:voicemail","carbon:volume-block-storage","carbon:volume-down","carbon:volume-down-alt","carbon:volume-down-filled","carbon:volume-down-filled-alt","carbon:volume-file-storage","carbon:volume-mute","carbon:volume-mute-filled","carbon:volume-object-storage","carbon:volume-up","carbon:volume-up-alt","carbon:volume-up-filled","carbon:volume-up-filled-alt","carbon:vpn","carbon:vpn-connection","carbon:vpn-policy","carbon:wallet","carbon:warning","carbon:warning-alt","carbon:warning-alt-filled","carbon:warning-alt-inverted","carbon:warning-alt-inverted-filled","carbon:warning-diamond","carbon:warning-filled","carbon:warning-hex","carbon:warning-hex-filled","carbon:warning-multiple","carbon:warning-other","carbon:warning-square","carbon:warning-square-filled","carbon:watch","carbon:watson","carbon:watson-machine-learning","carbon:watsonx","carbon:watsonx-ai","carbon:watsonx-data","carbon:watsonx-governance","carbon:wave-direction","carbon:wave-height","carbon:wave-period","carbon:weather-front-cold","carbon:weather-front-stationary","carbon:weather-front-warm","carbon:weather-station","carbon:web-services-cluster","carbon:web-services-container","carbon:web-services-definition","carbon:web-services-service","carbon:web-services-task","carbon:web-services-task-definition-version","carbon:webhook","carbon:websheet","carbon:wheat","carbon:white-paper","carbon:wifi","carbon:wifi-bridge","carbon:wifi-bridge-alt","carbon:wifi-controller","carbon:wifi-not-secure","carbon:wifi-off","carbon:wifi-secure","carbon:wikis","carbon:wind-gusts","carbon:wind-power","carbon:wind-stream","carbon:window-auto","carbon:window-base","carbon:window-black-saturation","carbon:window-overlay","carbon:window-preset","carbon:windy","carbon:windy-dust","carbon:windy-snow","carbon:windy-strong","carbon:winter-warning","carbon:wintry-mix","carbon:wireless-checkout","carbon:wmv","carbon:word-cloud","carbon:workflow-automation","carbon:workspace","carbon:workspace-import","carbon:worship","carbon:worship-christian","carbon:worship-jewish","carbon:worship-muslim","carbon:x","carbon:x-axis","carbon:xls","carbon:xml","carbon:y","carbon:y-axis","carbon:z","carbon:z-axis","carbon:z-lpar","carbon:z-systems","carbon:zip","carbon:zip-reference","carbon:zoom-area","carbon:zoom-fit","carbon:zoom-in","carbon:zoom-in-area","carbon:zoom-out","carbon:zoom-out-area","carbon:zoom-pan","carbon:zoom-reset","carbon:zos","carbon:zos-sysplex","fluent-mdl2:remove-from-trash","mdi:content-save","mdi:map-marker","ph:map-pin-fill","simple-icons:tiktok"] as const +export const iconList = ["carbon:3d-cursor","carbon:3d-cursor-alt","carbon:3d-curve-auto-colon","carbon:3d-curve-auto-vessels","carbon:3d-curve-manual","carbon:3d-ica","carbon:3d-mpr-toggle","carbon:3d-print-mesh","carbon:3d-software","carbon:3rd-party-connected","carbon:4k","carbon:4k-filled","carbon:accessibility","carbon:accessibility-alt","carbon:accessibility-color","carbon:accessibility-color-filled","carbon:account","carbon:accumulation-ice","carbon:accumulation-precipitation","carbon:accumulation-rain","carbon:accumulation-snow","carbon:activity","carbon:add","carbon:add-alt","carbon:add-comment","carbon:add-filled","carbon:add-large","carbon:agriculture-analytics","carbon:ai","carbon:ai-governance-lifecycle","carbon:ai-governance-tracked","carbon:ai-governance-untracked","carbon:ai-launch","carbon:ai-results","carbon:ai-results-high","carbon:ai-results-low","carbon:ai-results-medium","carbon:ai-results-urgent","carbon:ai-results-very-high","carbon:ai-status","carbon:ai-status-complete","carbon:ai-status-failed","carbon:ai-status-in-progress","carbon:ai-status-queued","carbon:ai-status-rejected","carbon:airline-digital-gate","carbon:airline-manage-gates","carbon:airline-passenger-care","carbon:airline-rapid-board","carbon:airplay","carbon:airplay-filled","carbon:airport-01","carbon:airport-02","carbon:airport-location","carbon:alarm","carbon:alarm-add","carbon:alarm-subtract","carbon:align-box-bottom-center","carbon:align-box-bottom-left","carbon:align-box-bottom-right","carbon:align-box-middle-center","carbon:align-box-middle-left","carbon:align-box-middle-right","carbon:align-box-top-center","carbon:align-box-top-left","carbon:align-box-top-right","carbon:align-horizontal-center","carbon:align-horizontal-left","carbon:align-horizontal-right","carbon:align-vertical-bottom","carbon:align-vertical-center","carbon:align-vertical-top","carbon:analytics","carbon:analytics-custom","carbon:analytics-reference","carbon:angle","carbon:annotation-visibility","carbon:aperture","carbon:api","carbon:api-1","carbon:app","carbon:app-connectivity","carbon:app-switcher","carbon:apple","carbon:apple-dash","carbon:application","carbon:application-mobile","carbon:application-virtual","carbon:application-web","carbon:apps","carbon:archive","carbon:area","carbon:area-custom","carbon:arithmetic-mean","carbon:arithmetic-median","carbon:arrival","carbon:arrow-annotation","carbon:arrow-down","carbon:arrow-down-left","carbon:arrow-down-right","carbon:arrow-left","carbon:arrow-right","carbon:arrow-shift-down","carbon:arrow-up","carbon:arrow-up-left","carbon:arrow-up-right","carbon:arrows","carbon:arrows-horizontal","carbon:arrows-vertical","carbon:asleep","carbon:asleep-filled","carbon:assembly","carbon:assembly-cluster","carbon:assembly-reference","carbon:asset","carbon:asset-confirm","carbon:asset-digital-twin","carbon:asset-view","carbon:asterisk","carbon:async","carbon:at","carbon:attachment","carbon:audio-console","carbon:augmented-reality","carbon:auto-scroll","carbon:automatic","carbon:autoscaling","carbon:awake","carbon:back-to-top","carbon:badge","carbon:baggage-claim","carbon:bar","carbon:barcode","carbon:bare-metal-server","carbon:bare-metal-server-01","carbon:bare-metal-server-02","carbon:barrier","carbon:basketball","carbon:bastion-host","carbon:bat","carbon:batch-job","carbon:batch-job-step","carbon:battery-charging","carbon:battery-empty","carbon:battery-full","carbon:battery-half","carbon:battery-low","carbon:battery-quarter","carbon:bee","carbon:bee-bat","carbon:beta","carbon:bicycle","carbon:binoculars","carbon:bloch-sphere","carbon:block-storage","carbon:block-storage-alt","carbon:blockchain","carbon:blog","carbon:bluetooth","carbon:bluetooth-off","carbon:book","carbon:bookmark","carbon:bookmark-add","carbon:bookmark-filled","carbon:boolean","carbon:boot","carbon:boot-volume","carbon:boot-volume-alt","carbon:border-bottom","carbon:border-full","carbon:border-left","carbon:border-none","carbon:border-right","carbon:border-top","carbon:bot","carbon:bottles-01","carbon:bottles-01-dash","carbon:bottles-02","carbon:bottles-02-dash","carbon:bottles-container","carbon:box","carbon:box-extra-large","carbon:box-large","carbon:box-medium","carbon:box-plot","carbon:box-small","carbon:branch","carbon:breaking-change","carbon:brightness-contrast","carbon:bring-forward","carbon:bring-to-front","carbon:brush-freehand","carbon:brush-polygon","carbon:build-tool","carbon:building","carbon:building-insights-1","carbon:building-insights-2","carbon:building-insights-3","carbon:bullhorn","carbon:buoy","carbon:bus","carbon:business-processes","carbon:button-centered","carbon:button-flush-left","carbon:cabin-care","carbon:cabin-care-alert","carbon:cabin-care-alt","carbon:cad","carbon:cafe","carbon:calculation","carbon:calculation-alt","carbon:calculator","carbon:calculator-check","carbon:calendar","carbon:calendar-add","carbon:calendar-add-alt","carbon:calendar-heat-map","carbon:calendar-settings","carbon:calendar-tools","carbon:calibrate","carbon:calls","carbon:calls-all","carbon:calls-incoming","carbon:camera","carbon:camera-action","carbon:campsite","carbon:car","carbon:car-front","carbon:carbon","carbon:carbon-accounting","carbon:carbon-for-ibm-dotcom","carbon:carbon-for-ibm-product","carbon:carbon-for-mobile","carbon:carbon-for-salesforce","carbon:carbon-ui-builder","carbon:caret-down","carbon:caret-left","carbon:caret-right","carbon:caret-sort","carbon:caret-sort-down","carbon:caret-sort-up","carbon:caret-up","carbon:carousel-horizontal","carbon:carousel-vertical","carbon:catalog","carbon:catalog-publish","carbon:categories","carbon:category","carbon:category-add","carbon:category-and","carbon:category-new","carbon:category-new-each","carbon:ccx","carbon:cd-archive","carbon:cd-create-archive","carbon:cd-create-exchange","carbon:cda","carbon:cell-tower","carbon:center-circle","carbon:center-square","carbon:center-to-fit","carbon:certificate","carbon:certificate-check","carbon:change-catalog","carbon:character-decimal","carbon:character-fraction","carbon:character-integer","carbon:character-lower-case","carbon:character-negative-number","carbon:character-patterns","carbon:character-sentence-case","carbon:character-upper-case","carbon:character-whole-number","carbon:charging-station","carbon:charging-station-filled","carbon:chart-3d","carbon:chart-area","carbon:chart-area-smooth","carbon:chart-area-stepper","carbon:chart-average","carbon:chart-bar","carbon:chart-bar-floating","carbon:chart-bar-overlay","carbon:chart-bar-stacked","carbon:chart-bar-target","carbon:chart-bubble","carbon:chart-bubble-packed","carbon:chart-bullet","carbon:chart-candlestick","carbon:chart-cluster-bar","carbon:chart-column","carbon:chart-column-floating","carbon:chart-column-target","carbon:chart-combo","carbon:chart-combo-stacked","carbon:chart-custom","carbon:chart-dual-y-axis","carbon:chart-error-bar","carbon:chart-error-bar-alt","carbon:chart-evaluation","carbon:chart-high-low","carbon:chart-histogram","carbon:chart-line","carbon:chart-line-data","carbon:chart-line-smooth","carbon:chart-logistic-regression","carbon:chart-marimekko","carbon:chart-maximum","carbon:chart-median","carbon:chart-minimum","carbon:chart-multi-line","carbon:chart-multitype","carbon:chart-network","carbon:chart-parallel","carbon:chart-pie","carbon:chart-planning-waterfall","carbon:chart-point","carbon:chart-population","carbon:chart-radar","carbon:chart-radial","carbon:chart-relationship","carbon:chart-ring","carbon:chart-river","carbon:chart-rose","carbon:chart-scatter","carbon:chart-spiral","carbon:chart-stacked","carbon:chart-stepper","carbon:chart-sunburst","carbon:chart-t-sne","carbon:chart-treemap","carbon:chart-venn-diagram","carbon:chart-violin-plot","carbon:chart-waterfall","carbon:chart-win-loss","carbon:chat","carbon:chat-bot","carbon:chat-launch","carbon:chat-off","carbon:chat-operational","carbon:checkbox","carbon:checkbox-checked","carbon:checkbox-checked-filled","carbon:checkbox-indeterminate","carbon:checkbox-indeterminate-filled","carbon:checkbox-undeterminate","carbon:checkbox-undeterminate-filled","carbon:checkmark","carbon:checkmark-filled","carbon:checkmark-filled-error","carbon:checkmark-filled-warning","carbon:checkmark-outline","carbon:checkmark-outline-error","carbon:checkmark-outline-warning","carbon:chemistry","carbon:chemistry-reference","carbon:chevron-down","carbon:chevron-down-outline","carbon:chevron-left","carbon:chevron-mini","carbon:chevron-right","carbon:chevron-sort","carbon:chevron-sort-down","carbon:chevron-sort-up","carbon:chevron-up","carbon:chevron-up-outline","carbon:chip","carbon:choices","carbon:choose-item","carbon:choropleth-map","carbon:cics-cmas","carbon:cics-db2-connection","carbon:cics-explorer","carbon:cics-program","carbon:cics-region","carbon:cics-region-alt","carbon:cics-region-routing","carbon:cics-region-target","carbon:cics-sit","carbon:cics-sit-overrides","carbon:cics-system-group","carbon:cics-transaction-server-zos","carbon:cics-wui-region","carbon:cicsplex","carbon:circle-dash","carbon:circle-filled","carbon:circle-measurement","carbon:circle-outline","carbon:circle-packing","carbon:circle-solid","carbon:circuit-composer","carbon:classification","carbon:classifier-language","carbon:clean","carbon:close","carbon:close-filled","carbon:close-large","carbon:close-outline","carbon:closed-caption","carbon:closed-caption-alt","carbon:closed-caption-filled","carbon:cloud","carbon:cloud-alerting","carbon:cloud-app","carbon:cloud-auditing","carbon:cloud-ceiling","carbon:cloud-data-ops","carbon:cloud-download","carbon:cloud-foundry-1","carbon:cloud-foundry-2","carbon:cloud-lightning","carbon:cloud-logging","carbon:cloud-monitoring","carbon:cloud-offline","carbon:cloud-rain","carbon:cloud-registry","carbon:cloud-satellite","carbon:cloud-satellite-config","carbon:cloud-satellite-link","carbon:cloud-satellite-services","carbon:cloud-service-management","carbon:cloud-services","carbon:cloud-snow","carbon:cloud-upload","carbon:cloudy","carbon:cobb-angle","carbon:code","carbon:code-hide","carbon:code-reference","carbon:code-signing-service","carbon:cognitive","carbon:collaborate","carbon:collapse-all","carbon:collapse-categories","carbon:color-palette","carbon:color-switch","carbon:column","carbon:column-delete","carbon:column-dependency","carbon:column-insert","carbon:commit","carbon:communication-unified","carbon:compare","carbon:compass","carbon:composer-edit","carbon:concept","carbon:condition-point","carbon:condition-wait-point","carbon:connect","carbon:connect-recursive","carbon:connect-reference","carbon:connect-source","carbon:connect-target","carbon:connection-receive","carbon:connection-send","carbon:connection-signal","carbon:connection-signal-off","carbon:connection-two-way","carbon:construction","carbon:container-registry","carbon:container-services","carbon:container-software","carbon:content-delivery-network","carbon:content-view","carbon:continue","carbon:continue-filled","carbon:continuous-deployment","carbon:continuous-integration","carbon:contour-draw","carbon:contour-edit","carbon:contour-finding","carbon:contrast","carbon:convert-to-cloud","carbon:cookie","carbon:copy","carbon:copy-file","carbon:copy-link","carbon:corn","carbon:corner","carbon:coronavirus","carbon:cost","carbon:cost-total","carbon:cough","carbon:course","carbon:covariate","carbon:credentials","carbon:crop","carbon:crop-growth","carbon:crop-health","carbon:cross-reference","carbon:cross-tab","carbon:crossroads","carbon:crowd-report","carbon:crowd-report-filled","carbon:csv","carbon:cu1","carbon:cu3","carbon:cube","carbon:cube-view","carbon:currency","carbon:currency-baht","carbon:currency-dollar","carbon:currency-euro","carbon:currency-lira","carbon:currency-pound","carbon:currency-ruble","carbon:currency-rupee","carbon:currency-shekel","carbon:currency-won","carbon:currency-yen","carbon:cursor-1","carbon:cursor-2","carbon:customer","carbon:customer-service","carbon:cut","carbon:cut-in-half","carbon:cut-out","carbon:cy","carbon:cyclist","carbon:cz","carbon:dashboard","carbon:dashboard-reference","carbon:data-1","carbon:data-2","carbon:data-accessor","carbon:data-analytics","carbon:data-backup","carbon:data-base","carbon:data-base-alt","carbon:data-bin","carbon:data-blob","carbon:data-categorical","carbon:data-center","carbon:data-check","carbon:data-class","carbon:data-collection","carbon:data-connected","carbon:data-definition","carbon:data-diode","carbon:data-enrichment","carbon:data-enrichment-add","carbon:data-error","carbon:data-format","carbon:data-player","carbon:data-quality-definition","carbon:data-reference","carbon:data-refinery","carbon:data-refinery-reference","carbon:data-regular","carbon:data-set","carbon:data-share","carbon:data-structured","carbon:data-table","carbon:data-table-reference","carbon:data-unreal","carbon:data-unstructured","carbon:data-view","carbon:data-view-alt","carbon:data-vis-1","carbon:data-vis-2","carbon:data-vis-3","carbon:data-vis-4","carbon:data-volume","carbon:data-volume-alt","carbon:database-datastax","carbon:database-elastic","carbon:database-enterprise-db2","carbon:database-enterprisedb","carbon:database-etcd","carbon:database-messaging","carbon:database-mongodb","carbon:database-postgresql","carbon:database-rabbit","carbon:database-redis","carbon:datastore","carbon:db2-buffer-pool","carbon:db2-data-sharing-group","carbon:db2-database","carbon:debug","carbon:decision-tree","carbon:delete","carbon:delivery","carbon:delivery-add","carbon:delivery-parcel","carbon:delivery-truck","carbon:demo","carbon:denominate","carbon:departure","carbon:deploy","carbon:deploy-rules","carbon:deployment-pattern","carbon:deployment-policy","carbon:deployment-unit-data","carbon:deployment-unit-execution","carbon:deployment-unit-installation","carbon:deployment-unit-presentation","carbon:deployment-unit-technical-data","carbon:deployment-unit-technical-execution","carbon:deployment-unit-technical-installation","carbon:deployment-unit-technical-presentation","carbon:desk-adjustable","carbon:development","carbon:devices","carbon:devices-apps","carbon:dew-point","carbon:dew-point-filled","carbon:diagram","carbon:diagram-reference","carbon:diamond-outline","carbon:diamond-solid","carbon:dicom-6000","carbon:dicom-overlay","carbon:direct-link","carbon:direction-bear-right-01","carbon:direction-bear-right-01-filled","carbon:direction-bear-right-02","carbon:direction-bear-right-02-filled","carbon:direction-curve","carbon:direction-curve-filled","carbon:direction-fork","carbon:direction-fork-filled","carbon:direction-loop-left","carbon:direction-loop-left-filled","carbon:direction-loop-right","carbon:direction-loop-right-filled","carbon:direction-merge","carbon:direction-merge-filled","carbon:direction-right-01","carbon:direction-right-01-filled","carbon:direction-right-02","carbon:direction-right-02-filled","carbon:direction-rotary-first-right","carbon:direction-rotary-first-right-filled","carbon:direction-rotary-right","carbon:direction-rotary-right-filled","carbon:direction-rotary-straight","carbon:direction-rotary-straight-filled","carbon:direction-sharp-turn","carbon:direction-sharp-turn-filled","carbon:direction-straight","carbon:direction-straight-filled","carbon:direction-straight-right","carbon:direction-straight-right-filled","carbon:direction-u-turn","carbon:direction-u-turn-filled","carbon:directory-domain","carbon:distribute-horizontal-center","carbon:distribute-horizontal-left","carbon:distribute-horizontal-right","carbon:distribute-vertical-bottom","carbon:distribute-vertical-center","carbon:distribute-vertical-top","carbon:dna","carbon:dns-services","carbon:doc","carbon:document","carbon:document-add","carbon:document-attachment","carbon:document-audio","carbon:document-blank","carbon:document-download","carbon:document-epdf","carbon:document-export","carbon:document-horizontal","carbon:document-import","carbon:document-multiple-01","carbon:document-multiple-02","carbon:document-pdf","carbon:document-preliminary","carbon:document-protected","carbon:document-security","carbon:document-sentiment","carbon:document-signed","carbon:document-sketch","carbon:document-subtract","carbon:document-tasks","carbon:document-unknown","carbon:document-unprotected","carbon:document-vertical","carbon:document-video","carbon:document-view","carbon:document-word-processor","carbon:document-word-processor-reference","carbon:dog-walker","carbon:dot-mark","carbon:double-integer","carbon:down-to-bottom","carbon:download","carbon:download-study","carbon:downstream","carbon:drag-horizontal","carbon:drag-vertical","carbon:draggable","carbon:draw","carbon:drill-back","carbon:drill-down","carbon:drill-through","carbon:drink-01","carbon:drink-02","carbon:driver-analysis","carbon:drone","carbon:drone-delivery","carbon:drone-front","carbon:drone-video","carbon:drop-photo","carbon:drop-photo-filled","carbon:drought","carbon:dvr","carbon:earth","carbon:earth-americas","carbon:earth-americas-filled","carbon:earth-europe-africa","carbon:earth-europe-africa-filled","carbon:earth-filled","carbon:earth-southeast-asia","carbon:earth-southeast-asia-filled","carbon:earthquake","carbon:edge-cluster","carbon:edge-device","carbon:edge-enhancement","carbon:edge-enhancement-01","carbon:edge-enhancement-02","carbon:edge-enhancement-03","carbon:edge-node","carbon:edge-node-alt","carbon:edge-service","carbon:edit","carbon:edit-filter","carbon:edit-off","carbon:edt-loop","carbon:education","carbon:email","carbon:email-new","carbon:encryption","carbon:energy-renewable","carbon:enterprise","carbon:equal-approximately","carbon:equalizer","carbon:erase","carbon:erase-3d","carbon:error","carbon:error-filled","carbon:error-outline","carbon:event","carbon:event-change","carbon:event-incident","carbon:event-schedule","carbon:event-warning","carbon:events","carbon:events-alt","carbon:exam-mode","carbon:executable-program","carbon:exit","carbon:expand-all","carbon:expand-categories","carbon:explore","carbon:export","carbon:eyedropper","carbon:face-activated","carbon:face-activated-add","carbon:face-activated-filled","carbon:face-add","carbon:face-cool","carbon:face-dissatisfied","carbon:face-dissatisfied-filled","carbon:face-dizzy","carbon:face-dizzy-filled","carbon:face-mask","carbon:face-neutral","carbon:face-neutral-filled","carbon:face-pending","carbon:face-pending-filled","carbon:face-satisfied","carbon:face-satisfied-filled","carbon:face-wink","carbon:face-wink-filled","carbon:factor","carbon:fade","carbon:favorite","carbon:favorite-filled","carbon:favorite-half","carbon:fetch-upload","carbon:fetch-upload-cloud","carbon:file-storage","carbon:filter","carbon:filter-edit","carbon:filter-remove","carbon:filter-reset","carbon:finance","carbon:fingerprint-recognition","carbon:fire","carbon:firewall","carbon:firewall-classic","carbon:fish","carbon:fish-multiple","carbon:fit-to-height","carbon:fit-to-screen","carbon:fit-to-width","carbon:flag","carbon:flag-filled","carbon:flagging-taxi","carbon:flash","carbon:flash-filled","carbon:flash-off","carbon:flash-off-filled","carbon:flight-international","carbon:flight-roster","carbon:flight-schedule","carbon:floating-ip","carbon:flood","carbon:flood-warning","carbon:floorplan","carbon:flow","carbon:flow-connection","carbon:flow-data","carbon:flow-logs-vpc","carbon:flow-modeler","carbon:flow-modeler-reference","carbon:flow-stream","carbon:flow-stream-reference","carbon:fog","carbon:folder","carbon:folder-add","carbon:folder-details","carbon:folder-details-reference","carbon:folder-move-to","carbon:folder-off","carbon:folder-open","carbon:folder-parent","carbon:folder-shared","carbon:folders","carbon:forecast-hail","carbon:forecast-hail-30","carbon:forecast-lightning","carbon:forecast-lightning-30","carbon:fork","carbon:forum","carbon:forward-10","carbon:forward-30","carbon:forward-5","carbon:foundation-model","carbon:fragile","carbon:friendship","carbon:fruit-bowl","carbon:function","carbon:function-math","carbon:fusion-blender","carbon:game-console","carbon:game-wireless","carbon:gamification","carbon:gas-station","carbon:gas-station-filled","carbon:gateway","carbon:gateway-api","carbon:gateway-mail","carbon:gateway-public","carbon:gateway-security","carbon:gateway-user-access","carbon:gateway-vpn","carbon:gender-female","carbon:gender-male","carbon:generate-pdf","carbon:gif","carbon:gift","carbon:global-loan-and-trial","carbon:globe","carbon:gradient","carbon:graphical-data-flow","carbon:grid","carbon:group","carbon:group-access","carbon:group-account","carbon:group-objects","carbon:group-objects-new","carbon:group-objects-save","carbon:group-presentation","carbon:group-resource","carbon:group-security","carbon:growth","carbon:gui","carbon:gui-management","carbon:h","carbon:hail","carbon:hanging-protocol","carbon:harbor","carbon:hardware-security-module","carbon:hashtag","carbon:haze","carbon:haze-night","carbon:hd","carbon:hd-filled","carbon:hdr","carbon:headphones","carbon:headset","carbon:health-cross","carbon:hearing","carbon:heat-map","carbon:heat-map-02","carbon:heat-map-03","carbon:heat-map-stocks","carbon:helicopter","carbon:help","carbon:help-desk","carbon:help-filled","carbon:hexagon-outline","carbon:hexagon-solid","carbon:hexagon-vertical-outline","carbon:hexagon-vertical-solid","carbon:hinton-plot","carbon:hl7-attributes","carbon:hole-filling","carbon:hole-filling-cursor","carbon:home","carbon:horizontal-view","carbon:hospital","carbon:hospital-bed","carbon:hotel","carbon:hourglass","carbon:html","carbon:html-reference","carbon:http","carbon:humidity","carbon:humidity-alt","carbon:hurricane","carbon:hybrid-networking","carbon:hybrid-networking-alt","carbon:ibm-ai-on-z","carbon:ibm-aiops-insights","carbon:ibm-bluepay","carbon:ibm-cloud","carbon:ibm-cloud-app-id","carbon:ibm-cloud-bare-metal-server","carbon:ibm-cloud-bare-metal-servers-vpc","carbon:ibm-cloud-citrix-daas","carbon:ibm-cloud-continuous-delivery","carbon:ibm-cloud-dedicated-host","carbon:ibm-cloud-direct-link-1-connect","carbon:ibm-cloud-direct-link-1-dedicated","carbon:ibm-cloud-direct-link-1-dedicated-hosting","carbon:ibm-cloud-direct-link-1-exchange","carbon:ibm-cloud-direct-link-2-connect","carbon:ibm-cloud-direct-link-2-dedicated","carbon:ibm-cloud-direct-link-2-dedicated-hosting","carbon:ibm-cloud-event-notification","carbon:ibm-cloud-event-streams","carbon:ibm-cloud-for-education","carbon:ibm-cloud-hpc","carbon:ibm-cloud-hsm","carbon:ibm-cloud-hyper-protect-crypto-services","carbon:ibm-cloud-hyper-protect-dbaas","carbon:ibm-cloud-hyper-protect-vs","carbon:ibm-cloud-internet-services","carbon:ibm-cloud-ipsec-vpn","carbon:ibm-cloud-key-protect","carbon:ibm-cloud-kubernetes-service","carbon:ibm-cloud-logging","carbon:ibm-cloud-mass-data-migration","carbon:ibm-cloud-pak-applications","carbon:ibm-cloud-pak-business-automation","carbon:ibm-cloud-pak-data","carbon:ibm-cloud-pak-integration","carbon:ibm-cloud-pak-manta-automated-data-lineage","carbon:ibm-cloud-pak-multicloud-mgmt","carbon:ibm-cloud-pak-netezza","carbon:ibm-cloud-pak-network-automation","carbon:ibm-cloud-pak-security","carbon:ibm-cloud-pak-system","carbon:ibm-cloud-pak-watson-aiops","carbon:ibm-cloud-pal","carbon:ibm-cloud-privileged-access-gateway","carbon:ibm-cloud-projects","carbon:ibm-cloud-resiliency","carbon:ibm-cloud-secrets-manager","carbon:ibm-cloud-security-compliance-center","carbon:ibm-cloud-security-compliance-center-workload-protection","carbon:ibm-cloud-subnets","carbon:ibm-cloud-sysdig-secure","carbon:ibm-cloud-transit-gateway","carbon:ibm-cloud-virtual-server-classic","carbon:ibm-cloud-virtual-server-vpc","carbon:ibm-cloud-vpc","carbon:ibm-cloud-vpc-endpoints","carbon:ibm-cloudant","carbon:ibm-content-services","carbon:ibm-data-product-exchange","carbon:ibm-data-replication","carbon:ibm-datastage","carbon:ibm-db2","carbon:ibm-db2-alt","carbon:ibm-db2-warehouse","carbon:ibm-dynamic-route-server","carbon:ibm-engineering-systems-design-rhapsody-model-manager","carbon:ibm-engineering-systems-design-rhapsody-sn1","carbon:ibm-engineering-systems-design-rhapsody-sn2","carbon:ibm-event-automation","carbon:ibm-event-endpoint-mgmt","carbon:ibm-event-processing","carbon:ibm-event-streams","carbon:ibm-ibv","carbon:ibm-instana","carbon:ibm-match-360","carbon:ibm-mq","carbon:ibm-open-enterprise-languages","carbon:ibm-openshift-container-platform-on-vpc-for-regulated-industries","carbon:ibm-power-vs","carbon:ibm-power-vs-private-cloud","carbon:ibm-power-with-vpc","carbon:ibm-private-path-services","carbon:ibm-process-mining","carbon:ibm-saas-console","carbon:ibm-sap-on-power","carbon:ibm-secure-infrastructure-on-vpc-for-regulated-industries","carbon:ibm-security","carbon:ibm-security-services","carbon:ibm-telehealth","carbon:ibm-tenet","carbon:ibm-toolchain","carbon:ibm-turbonomic","carbon:ibm-vpn-for-vpc","carbon:ibm-vsi-on-vpc-for-regulated-industries","carbon:ibm-watson-assistant","carbon:ibm-watson-discovery","carbon:ibm-watson-knowledge-catalog","carbon:ibm-watson-knowledge-studio","carbon:ibm-watson-language-translator","carbon:ibm-watson-machine-learning","carbon:ibm-watson-natural-language-classifier","carbon:ibm-watson-natural-language-understanding","carbon:ibm-watson-openscale","carbon:ibm-watson-orders","carbon:ibm-watson-query","carbon:ibm-watson-speech-to-text","carbon:ibm-watson-studio","carbon:ibm-watson-text-to-speech","carbon:ibm-watson-tone-analyzer","carbon:ibm-watsonx-assistant","carbon:ibm-watsonx-code-assistant","carbon:ibm-watsonx-code-assistant-for-z","carbon:ibm-watsonx-code-assistant-for-z-refactor","carbon:ibm-watsonx-orchestrate","carbon:ibm-wazi-deploy","carbon:ibm-z-cloud-mod-stack","carbon:ibm-z-cloud-provisioning","carbon:ibm-z-environments-dev-sec-ops","carbon:ibm-z-os","carbon:ibm-z-os-ai-control-interface","carbon:ibm-z-os-containers","carbon:ibm-z-os-package-manager","carbon:ibm-z-processor-capacity-reference","carbon:ica-2d","carbon:ice-accretion","carbon:ice-vision","carbon:id","carbon:id-management","carbon:idea","carbon:identification","carbon:image","carbon:image-copy","carbon:image-medical","carbon:image-reference","carbon:image-search","carbon:image-search-alt","carbon:image-service","carbon:import-export","carbon:improve-relevance","carbon:in-progress","carbon:in-progress-error","carbon:in-progress-warning","carbon:incomplete","carbon:incomplete-cancel","carbon:incomplete-error","carbon:incomplete-warning","carbon:increase-level","carbon:industry","carbon:infinity","carbon:infinity-symbol","carbon:information","carbon:information-disabled","carbon:information-filled","carbon:information-square","carbon:information-square-filled","carbon:infrastructure-classic","carbon:insert","carbon:insert-page","carbon:insert-syntax","carbon:inspection","carbon:instance-bx","carbon:instance-classic","carbon:instance-cx","carbon:instance-mx","carbon:instance-virtual","carbon:integration","carbon:intent-request-active","carbon:intent-request-create","carbon:intent-request-heal","carbon:intent-request-inactive","carbon:intent-request-scale-in","carbon:intent-request-scale-out","carbon:intent-request-uninstall","carbon:intent-request-upgrade","carbon:interactions","carbon:interactive-segmentation-cursor","carbon:intersect","carbon:intrusion-prevention","carbon:inventory-management","carbon:iot-connect","carbon:iot-platform","carbon:ip","carbon:iso","carbon:iso-filled","carbon:iso-outline","carbon:join-full","carbon:join-inner","carbon:join-left","carbon:join-outer","carbon:join-right","carbon:jpg","carbon:js-error","carbon:json","carbon:json-reference","carbon:jump-link","carbon:keep-dry","carbon:keyboard","carbon:keyboard-off","carbon:kubernetes","carbon:kubernetes-ip-address","carbon:kubernetes-pod","carbon:label","carbon:language","carbon:laptop","carbon:lasso","carbon:lasso-polygon","carbon:launch","carbon:launch-study-1","carbon:launch-study-2","carbon:launch-study-3","carbon:layers","carbon:legend","carbon:letter-aa","carbon:letter-aa-large","carbon:letter-bb","carbon:letter-cc","carbon:letter-dd","carbon:letter-ee","carbon:letter-ff","carbon:letter-gg","carbon:letter-hh","carbon:letter-ii","carbon:letter-jj","carbon:letter-kk","carbon:letter-ll","carbon:letter-mm","carbon:letter-nn","carbon:letter-oo","carbon:letter-pp","carbon:letter-qq","carbon:letter-rr","carbon:letter-ss","carbon:letter-tt","carbon:letter-uu","carbon:letter-vv","carbon:letter-ww","carbon:letter-xx","carbon:letter-yy","carbon:letter-zz","carbon:license","carbon:license-draft","carbon:license-global","carbon:license-maintenance","carbon:license-maintenance-draft","carbon:license-third-party","carbon:license-third-party-draft","carbon:lifesaver","carbon:light","carbon:light-filled","carbon:lightning","carbon:link","carbon:linux","carbon:linux-alt","carbon:list","carbon:list-boxes","carbon:list-bulleted","carbon:list-checked","carbon:list-checked-mirror","carbon:list-dropdown","carbon:list-numbered","carbon:list-numbered-mirror","carbon:load-balancer-application","carbon:load-balancer-classic","carbon:load-balancer-global","carbon:load-balancer-listener","carbon:load-balancer-local","carbon:load-balancer-network","carbon:load-balancer-pool","carbon:load-balancer-vpc","carbon:location","carbon:location-company","carbon:location-company-filled","carbon:location-current","carbon:location-filled","carbon:location-hazard","carbon:location-hazard-filled","carbon:location-heart","carbon:location-heart-filled","carbon:location-person","carbon:location-person-filled","carbon:location-save","carbon:location-star","carbon:location-star-filled","carbon:locked","carbon:logical-partition","carbon:login","carbon:logo-angular","carbon:logo-ansible-community","carbon:logo-delicious","carbon:logo-digg","carbon:logo-discord","carbon:logo-facebook","carbon:logo-figma","carbon:logo-flickr","carbon:logo-github","carbon:logo-gitlab","carbon:logo-glassdoor","carbon:logo-google","carbon:logo-instagram","carbon:logo-invision","carbon:logo-jupyter","carbon:logo-keybase","carbon:logo-kubernetes","carbon:logo-linkedin","carbon:logo-livestream","carbon:logo-mastodon","carbon:logo-medium","carbon:logo-npm","carbon:logo-openshift","carbon:logo-pinterest","carbon:logo-python","carbon:logo-quora","carbon:logo-r-script","carbon:logo-react","carbon:logo-red-hat-ansible","carbon:logo-sketch","carbon:logo-skype","carbon:logo-slack","carbon:logo-snapchat","carbon:logo-stumbleupon","carbon:logo-svelte","carbon:logo-tumblr","carbon:logo-twitter","carbon:logo-vmware","carbon:logo-vmware-alt","carbon:logo-vue","carbon:logo-wechat","carbon:logo-x","carbon:logo-xing","carbon:logo-yelp","carbon:logo-youtube","carbon:logout","carbon:loop","carbon:mac","carbon:mac-command","carbon:mac-option","carbon:mac-shift","carbon:machine-learning","carbon:machine-learning-model","carbon:magic-wand","carbon:magic-wand-filled","carbon:magnify","carbon:mail-all","carbon:mail-reply","carbon:mammogram","carbon:mammogram-stacked","carbon:manage-protection","carbon:managed-solutions","carbon:map","carbon:map-boundary","carbon:map-boundary-vegetation","carbon:map-center","carbon:map-identify","carbon:marine-warning","carbon:math-curve","carbon:matrix","carbon:maximize","carbon:media-cast","carbon:media-library","carbon:media-library-filled","carbon:medication","carbon:medication-alert","carbon:medication-reminder","carbon:menu","carbon:message-queue","carbon:meter","carbon:meter-alt","carbon:microphone","carbon:microphone-filled","carbon:microphone-off","carbon:microphone-off-filled","carbon:microscope","carbon:microservices-1","carbon:microservices-2","carbon:migrate","carbon:migrate-alt","carbon:milestone","carbon:military-camp","carbon:minimize","carbon:misuse","carbon:misuse-alt","carbon:misuse-outline","carbon:mixed-rain-hail","carbon:mobile","carbon:mobile-add","carbon:mobile-audio","carbon:mobile-check","carbon:mobile-crash","carbon:mobile-download","carbon:mobile-event","carbon:mobile-landscape","carbon:mobile-request","carbon:mobile-session","carbon:mobile-view","carbon:mobile-view-orientation","carbon:mobility-services","carbon:model","carbon:model-alt","carbon:model-builder","carbon:model-builder-reference","carbon:model-reference","carbon:model-tuned","carbon:money","carbon:monster","carbon:monument","carbon:moon","carbon:moonrise","carbon:moonset","carbon:mostly-cloudy","carbon:mostly-cloudy-night","carbon:mountain","carbon:mov","carbon:move","carbon:movement","carbon:mp3","carbon:mp4","carbon:mpeg","carbon:mpg2","carbon:music","carbon:music-add","carbon:music-remove","carbon:mysql","carbon:name-space","carbon:navaid-civil","carbon:navaid-dme","carbon:navaid-helipad","carbon:navaid-military","carbon:navaid-military-civil","carbon:navaid-ndb","carbon:navaid-ndb-dme","carbon:navaid-private","carbon:navaid-seaplane","carbon:navaid-tacan","carbon:navaid-vhfor","carbon:navaid-vor","carbon:navaid-vordme","carbon:navaid-vortac","carbon:need","carbon:network-1","carbon:network-2","carbon:network-3","carbon:network-3-reference","carbon:network-4","carbon:network-4-reference","carbon:network-admin-control","carbon:network-enterprise","carbon:network-interface","carbon:network-overlay","carbon:network-public","carbon:new-tab","carbon:next-filled","carbon:next-outline","carbon:no-image","carbon:no-ticket","carbon:nominal","carbon:nominate","carbon:non-certified","carbon:noodle-bowl","carbon:not-available","carbon:not-sent","carbon:not-sent-filled","carbon:notebook","carbon:notebook-reference","carbon:notification","carbon:notification-filled","carbon:notification-new","carbon:notification-off","carbon:notification-off-filled","carbon:number-0","carbon:number-1","carbon:number-2","carbon:number-3","carbon:number-4","carbon:number-5","carbon:number-6","carbon:number-7","carbon:number-8","carbon:number-9","carbon:number-small-0","carbon:number-small-1","carbon:number-small-2","carbon:number-small-3","carbon:number-small-4","carbon:number-small-5","carbon:number-small-6","carbon:number-small-7","carbon:number-small-8","carbon:number-small-9","carbon:object-storage","carbon:object-storage-alt","carbon:observed-hail","carbon:observed-lightning","carbon:omega","carbon:opacity","carbon:open-panel-bottom","carbon:open-panel-filled-bottom","carbon:open-panel-filled-left","carbon:open-panel-filled-right","carbon:open-panel-filled-top","carbon:open-panel-left","carbon:open-panel-right","carbon:open-panel-top","carbon:operation","carbon:operation-gauge","carbon:operation-if","carbon:operations-field","carbon:operations-record","carbon:order-details","carbon:ordinal","carbon:outage","carbon:outlook-severe","carbon:overflow-menu-horizontal","carbon:overflow-menu-vertical","carbon:overlay","carbon:package","carbon:package-text-analysis","carbon:page-break","carbon:page-first","carbon:page-last","carbon:page-number","carbon:page-scroll","carbon:paint-brush","carbon:paint-brush-alt","carbon:palm-tree","carbon:pan-horizontal","carbon:pan-vertical","carbon:panel-expansion","carbon:paragraph","carbon:parameter","carbon:parent-child","carbon:partition-auto","carbon:partition-collection","carbon:partition-repartition","carbon:partition-same","carbon:partition-specific","carbon:partly-cloudy","carbon:partly-cloudy-night","carbon:partnership","carbon:passenger-drinks","carbon:passenger-plus","carbon:password","carbon:paste","carbon:pause","carbon:pause-filled","carbon:pause-future","carbon:pause-outline","carbon:pause-outline-filled","carbon:pause-past","carbon:pcn-e-node","carbon:pcn-military","carbon:pcn-p-node","carbon:pcn-z-node","carbon:pdf","carbon:pdf-reference","carbon:pedestrian","carbon:pedestrian-child","carbon:pedestrian-family","carbon:pen","carbon:pen-fountain","carbon:pending","carbon:pending-filled","carbon:pentagon-down-outline","carbon:pentagon-down-solid","carbon:pentagon-left-outline","carbon:pentagon-left-solid","carbon:pentagon-outline","carbon:pentagon-right-outline","carbon:pentagon-right-solid","carbon:pentagon-solid","carbon:percentage","carbon:percentage-filled","carbon:person","carbon:person-favorite","carbon:pest","carbon:pet-image-b","carbon:pet-image-o","carbon:phone","carbon:phone-application","carbon:phone-block","carbon:phone-block-filled","carbon:phone-filled","carbon:phone-incoming","carbon:phone-incoming-filled","carbon:phone-ip","carbon:phone-off","carbon:phone-off-filled","carbon:phone-outgoing","carbon:phone-outgoing-filled","carbon:phone-settings","carbon:phone-voice","carbon:phone-voice-filled","carbon:phrase-sentiment","carbon:picnic-area","carbon:piggy-bank","carbon:piggy-bank-slot","carbon:pills","carbon:pills-add","carbon:pills-subtract","carbon:pin","carbon:pin-filled","carbon:plan","carbon:plane","carbon:plane-private","carbon:plane-sea","carbon:platforms","carbon:play","carbon:play-filled","carbon:play-filled-alt","carbon:play-outline","carbon:play-outline-filled","carbon:playlist","carbon:plug","carbon:plug-filled","carbon:png","carbon:point-of-presence","carbon:pointer-text","carbon:police","carbon:policy","carbon:popup","carbon:port-input","carbon:port-output","carbon:portfolio","carbon:power","carbon:ppt","carbon:presentation-file","carbon:pressure","carbon:pressure-filled","carbon:previous-filled","carbon:previous-outline","carbon:printer","carbon:process","carbon:process-automate","carbon:product","carbon:progress-bar","carbon:progress-bar-round","carbon:promote","carbon:prompt-session","carbon:prompt-template","carbon:property-relationship","carbon:purchase","carbon:qc-launch","carbon:qq-plot","carbon:qr-code","carbon:quadrant-plot","carbon:query","carbon:query-queue","carbon:queued","carbon:quotes","carbon:radar","carbon:radar-enhanced","carbon:radar-weather","carbon:radio","carbon:radio-button","carbon:radio-button-checked","carbon:radio-combat","carbon:radio-push-to-talk","carbon:rain","carbon:rain-drizzle","carbon:rain-drop","carbon:rain-heavy","carbon:rain-scattered","carbon:rain-scattered-night","carbon:raw","carbon:receipt","carbon:recently-viewed","carbon:recommend","carbon:recording","carbon:recording-filled","carbon:recording-filled-alt","carbon:recycle","carbon:redo","carbon:ref-evapotranspiration","carbon:reference-architecture","carbon:reflect-horizontal","carbon:reflect-vertical","carbon:region-analysis-area","carbon:region-analysis-volume","carbon:registration","carbon:reminder","carbon:reminder-medical","carbon:renew","carbon:repeat","carbon:repeat-one","carbon:replicate","carbon:reply","carbon:reply-all","carbon:repo-artifact","carbon:repo-source-code","carbon:report","carbon:report-data","carbon:request-quote","carbon:research-bloch-sphere","carbon:research-hinton-plot","carbon:research-matrix","carbon:reset","carbon:reset-alt","carbon:restart","carbon:restaurant","carbon:restaurant-fine","carbon:result","carbon:result-draft","carbon:result-new","carbon:result-old","carbon:retry-failed","carbon:return","carbon:review","carbon:rewind-10","carbon:rewind-30","carbon:rewind-5","carbon:right-panel-close","carbon:right-panel-close-filled","carbon:right-panel-open","carbon:right-panel-open-filled","carbon:road","carbon:road-weather","carbon:roadmap","carbon:rocket","carbon:rotate","carbon:rotate-180","carbon:rotate-360","carbon:rotate-clockwise","carbon:rotate-clockwise-alt","carbon:rotate-clockwise-alt-filled","carbon:rotate-clockwise-filled","carbon:rotate-counterclockwise","carbon:rotate-counterclockwise-alt","carbon:rotate-counterclockwise-alt-filled","carbon:rotate-counterclockwise-filled","carbon:router","carbon:router-voice","carbon:router-wifi","carbon:row","carbon:row-collapse","carbon:row-delete","carbon:row-expand","carbon:row-insert","carbon:rss","carbon:rule","carbon:rule-cancelled","carbon:rule-data-quality","carbon:rule-draft","carbon:rule-filled","carbon:rule-locked","carbon:rule-partial","carbon:rule-test","carbon:ruler","carbon:ruler-alt","carbon:run","carbon:run-mirror","carbon:running","carbon:s","carbon:s-alt","carbon:sailboat-coastal","carbon:sailboat-offshore","carbon:sales-ops","carbon:sankey-diagram","carbon:sankey-diagram-alt","carbon:satellite","carbon:satellite-radar","carbon:satellite-weather","carbon:save","carbon:save-annotation","carbon:save-image","carbon:save-model","carbon:save-series","carbon:scale","carbon:scales","carbon:scales-tipped","carbon:scalpel","carbon:scalpel-cursor","carbon:scalpel-lasso","carbon:scalpel-select","carbon:scan","carbon:scan-alt","carbon:scan-disabled","carbon:scatter-matrix","carbon:schematics","carbon:scis-control-tower","carbon:scis-transparent-supply","carbon:scooter","carbon:scooter-front","carbon:screen","carbon:screen-map","carbon:screen-map-set","carbon:screen-off","carbon:script","carbon:script-reference","carbon:sdk","carbon:search","carbon:search-advanced","carbon:search-locate","carbon:search-locate-mirror","carbon:security","carbon:security-services","carbon:select-01","carbon:select-02","carbon:select-window","carbon:send","carbon:send-alt","carbon:send-alt-filled","carbon:send-backward","carbon:send-filled","carbon:send-to-back","carbon:server-dns","carbon:server-proxy","carbon:server-time","carbon:service-desk","carbon:service-id","carbon:service-levels","carbon:session-border-control","carbon:settings","carbon:settings-adjust","carbon:settings-check","carbon:settings-edit","carbon:settings-services","carbon:settings-view","carbon:shape-except","carbon:shape-exclude","carbon:shape-intersect","carbon:shape-join","carbon:shape-unite","carbon:share","carbon:share-knowledge","carbon:shopping-bag","carbon:shopping-cart","carbon:shopping-cart-arrow-down","carbon:shopping-cart-arrow-up","carbon:shopping-cart-clear","carbon:shopping-cart-error","carbon:shopping-cart-minus","carbon:shopping-cart-plus","carbon:shopping-catalog","carbon:show-data-cards","carbon:shrink-screen","carbon:shrink-screen-filled","carbon:shuffle","carbon:shuttle","carbon:side-panel-close","carbon:side-panel-close-filled","carbon:side-panel-open","carbon:side-panel-open-filled","carbon:sight","carbon:sigma","carbon:signal-strength","carbon:sim-card","carbon:skill-level","carbon:skill-level-advanced","carbon:skill-level-basic","carbon:skill-level-intermediate","carbon:skip-back","carbon:skip-back-filled","carbon:skip-back-outline","carbon:skip-back-outline-filled","carbon:skip-back-outline-solid","carbon:skip-back-solid-filled","carbon:skip-forward","carbon:skip-forward-filled","carbon:skip-forward-outline","carbon:skip-forward-outline-filled","carbon:skip-forward-outline-solid","carbon:skip-forward-solid-filled","carbon:sleet","carbon:slisor","carbon:slm","carbon:smell","carbon:smoke","carbon:smoothing","carbon:smoothing-cursor","carbon:snooze","carbon:snow","carbon:snow-blizzard","carbon:snow-density","carbon:snow-heavy","carbon:snow-scattered","carbon:snow-scattered-night","carbon:snowflake","carbon:soccer","carbon:software-resource","carbon:software-resource-cluster","carbon:software-resource-resource","carbon:soil-moisture","carbon:soil-moisture-field","carbon:soil-moisture-global","carbon:soil-temperature","carbon:soil-temperature-field","carbon:soil-temperature-global","carbon:solar-panel","carbon:sort-ascending","carbon:sort-descending","carbon:sort-remove","carbon:spell-check","carbon:spine-label","carbon:split","carbon:split-discard","carbon:split-screen","carbon:spray-paint","carbon:sprout","carbon:sql","carbon:square-outline","carbon:stack-limitation","carbon:stacked-move","carbon:stacked-scrolling-1","carbon:stacked-scrolling-2","carbon:stamp","carbon:star","carbon:star-filled","carbon:star-half","carbon:star-review","carbon:status-acknowledge","carbon:status-change","carbon:status-partial-fail","carbon:status-resolved","carbon:stay-inside","carbon:stem-leaf-plot","carbon:stethoscope","carbon:stop","carbon:stop-filled","carbon:stop-filled-alt","carbon:stop-outline","carbon:stop-outline-filled","carbon:stop-sign","carbon:stop-sign-filled","carbon:storage-pool","carbon:storage-request","carbon:store","carbon:storm-tracker","carbon:strawberry","carbon:stress-breath-editor","carbon:string-integer","carbon:string-text","carbon:study-next","carbon:study-previous","carbon:study-read","carbon:study-skip","carbon:study-transfer","carbon:study-unread","carbon:study-view","carbon:sub-volume","carbon:subdirectory","carbon:subflow","carbon:subflow-local","carbon:subnet-acl-rules","carbon:subtract","carbon:subtract-alt","carbon:subtract-filled","carbon:subtract-large","carbon:summary-kpi","carbon:summary-kpi-mirror","carbon:sun","carbon:sunny","carbon:sunrise","carbon:sunset","carbon:support-vector-machine","carbon:sustainability","carbon:svg","carbon:swim","carbon:switch-layer-2","carbon:switch-layer-3","carbon:switcher","carbon:sync-settings","carbon:sys-provision","carbon:t","carbon:t-alt","carbon:table","carbon:table-alias","carbon:table-built","carbon:table-of-contents","carbon:table-shortcut","carbon:table-split","carbon:tablet","carbon:tablet-landscape","carbon:tag","carbon:tag-edit","carbon:tag-export","carbon:tag-group","carbon:tag-import","carbon:tag-none","carbon:tank","carbon:task","carbon:task-add","carbon:task-approved","carbon:task-asset-view","carbon:task-complete","carbon:task-location","carbon:task-remove","carbon:task-settings","carbon:task-star","carbon:task-tools","carbon:task-view","carbon:taste","carbon:taxi","carbon:tcp-ip-service","carbon:temperature","carbon:temperature-celsius","carbon:temperature-celsius-alt","carbon:temperature-fahrenheit","carbon:temperature-fahrenheit-alt","carbon:temperature-feels-like","carbon:temperature-frigid","carbon:temperature-hot","carbon:temperature-inversion","carbon:temperature-max","carbon:temperature-min","carbon:temperature-water","carbon:template","carbon:tennis","carbon:tennis-ball","carbon:term","carbon:terminal","carbon:terminal-3270","carbon:test-tool","carbon:text-align-center","carbon:text-align-justify","carbon:text-align-left","carbon:text-align-mixed","carbon:text-align-right","carbon:text-all-caps","carbon:text-annotation-toggle","carbon:text-bold","carbon:text-clear-format","carbon:text-color","carbon:text-creation","carbon:text-fill","carbon:text-font","carbon:text-footnote","carbon:text-highlight","carbon:text-indent","carbon:text-indent-less","carbon:text-indent-more","carbon:text-italic","carbon:text-kerning","carbon:text-leading","carbon:text-line-spacing","carbon:text-link","carbon:text-link-analysis","carbon:text-long-paragraph","carbon:text-mining","carbon:text-mining-applier","carbon:text-new-line","carbon:text-scale","carbon:text-selection","carbon:text-short-paragraph","carbon:text-small-caps","carbon:text-strikethrough","carbon:text-subscript","carbon:text-superscript","carbon:text-tracking","carbon:text-underline","carbon:text-vertical-alignment","carbon:text-wrap","carbon:theater","carbon:this-side-up","carbon:threshold","carbon:thumbnail-1","carbon:thumbnail-2","carbon:thumbnail-preview","carbon:thumbs-down","carbon:thumbs-down-filled","carbon:thumbs-up","carbon:thumbs-up-filled","carbon:thunderstorm","carbon:thunderstorm-scattered","carbon:thunderstorm-scattered-night","carbon:thunderstorm-severe","carbon:thunderstorm-strong","carbon:ticket","carbon:tides","carbon:tif","carbon:time","carbon:time-filled","carbon:time-plot","carbon:timer","carbon:tool-box","carbon:tool-kit","carbon:tools","carbon:tools-alt","carbon:tornado","carbon:tornado-warning","carbon:touch-1","carbon:touch-1-down","carbon:touch-1-down-filled","carbon:touch-1-filled","carbon:touch-2","carbon:touch-2-filled","carbon:touch-interaction","carbon:tour","carbon:traffic-cone","carbon:traffic-event","carbon:traffic-flow","carbon:traffic-flow-incident","carbon:traffic-incident","carbon:traffic-weather-incident","carbon:train","carbon:train-heart","carbon:train-profile","carbon:train-speed","carbon:train-ticket","carbon:train-time","carbon:tram","carbon:transform-binary","carbon:transform-instructions","carbon:transform-language","carbon:transgender","carbon:translate","carbon:transmission-lte","carbon:transpose","carbon:trash-can","carbon:tree","carbon:tree-fall-risk","carbon:tree-view","carbon:tree-view-alt","carbon:triangle-down-outline","carbon:triangle-down-solid","carbon:triangle-left-outline","carbon:triangle-left-solid","carbon:triangle-outline","carbon:triangle-right-outline","carbon:triangle-right-solid","carbon:triangle-solid","carbon:trophy","carbon:trophy-filled","carbon:tropical-storm","carbon:tropical-storm-model-tracks","carbon:tropical-storm-tracks","carbon:tropical-warning","carbon:tsq","carbon:tsunami","carbon:tsv","carbon:tuning","carbon:two-factor-authentication","carbon:two-person-lift","carbon:txt","carbon:txt-reference","carbon:type-pattern","carbon:types","carbon:u1","carbon:u2","carbon:u3","carbon:umbrella","carbon:undefined","carbon:undefined-filled","carbon:undo","carbon:ungroup-objects","carbon:unknown","carbon:unknown-filled","carbon:unlink","carbon:unlocked","carbon:unsaved","carbon:up-to-top","carbon:update-now","carbon:upgrade","carbon:upload","carbon:upstream","carbon:url","carbon:usb","carbon:user","carbon:user-access","carbon:user-activity","carbon:user-admin","carbon:user-avatar","carbon:user-avatar-filled","carbon:user-avatar-filled-alt","carbon:user-certification","carbon:user-data","carbon:user-favorite","carbon:user-favorite-alt","carbon:user-favorite-alt-filled","carbon:user-filled","carbon:user-follow","carbon:user-identification","carbon:user-military","carbon:user-multiple","carbon:user-online","carbon:user-profile","carbon:user-profile-alt","carbon:user-role","carbon:user-service-desk","carbon:user-settings","carbon:user-simulation","carbon:user-speaker","carbon:user-sponsor","carbon:user-x-ray","carbon:uv-index","carbon:uv-index-alt","carbon:uv-index-filled","carbon:value-variable","carbon:van","carbon:vegetation-asset","carbon:vegetation-encroachment","carbon:vegetation-height","carbon:vehicle-api","carbon:vehicle-connected","carbon:vehicle-insights","carbon:vehicle-services","carbon:version","carbon:version-major","carbon:version-minor","carbon:version-patch","carbon:vertical-view","carbon:video","carbon:video-add","carbon:video-chat","carbon:video-filled","carbon:video-off","carbon:video-off-filled","carbon:video-player","carbon:view","carbon:view-filled","carbon:view-mode-1","carbon:view-mode-2","carbon:view-next","carbon:view-off","carbon:view-off-filled","carbon:virtual-column","carbon:virtual-column-key","carbon:virtual-desktop","carbon:virtual-machine","carbon:virtual-private-cloud","carbon:virtual-private-cloud-alt","carbon:visual-recognition","carbon:vlan","carbon:vlan-ibm","carbon:vmdk-disk","carbon:voice-activate","carbon:voicemail","carbon:volume-block-storage","carbon:volume-down","carbon:volume-down-alt","carbon:volume-down-filled","carbon:volume-down-filled-alt","carbon:volume-file-storage","carbon:volume-mute","carbon:volume-mute-filled","carbon:volume-object-storage","carbon:volume-up","carbon:volume-up-alt","carbon:volume-up-filled","carbon:volume-up-filled-alt","carbon:vpn","carbon:vpn-connection","carbon:vpn-policy","carbon:wallet","carbon:warning","carbon:warning-alt","carbon:warning-alt-filled","carbon:warning-alt-inverted","carbon:warning-alt-inverted-filled","carbon:warning-diamond","carbon:warning-filled","carbon:warning-hex","carbon:warning-hex-filled","carbon:warning-multiple","carbon:warning-other","carbon:warning-square","carbon:warning-square-filled","carbon:watch","carbon:watson","carbon:watson-machine-learning","carbon:watsonx","carbon:watsonx-ai","carbon:watsonx-data","carbon:watsonx-governance","carbon:wave-direction","carbon:wave-height","carbon:wave-period","carbon:weather-front-cold","carbon:weather-front-stationary","carbon:weather-front-warm","carbon:weather-station","carbon:web-services-cluster","carbon:web-services-container","carbon:web-services-definition","carbon:web-services-service","carbon:web-services-task","carbon:web-services-task-definition-version","carbon:webhook","carbon:websheet","carbon:wheat","carbon:white-paper","carbon:wifi","carbon:wifi-bridge","carbon:wifi-bridge-alt","carbon:wifi-controller","carbon:wifi-not-secure","carbon:wifi-off","carbon:wifi-secure","carbon:wikis","carbon:wind-gusts","carbon:wind-power","carbon:wind-stream","carbon:window-auto","carbon:window-base","carbon:window-black-saturation","carbon:window-overlay","carbon:window-preset","carbon:windy","carbon:windy-dust","carbon:windy-snow","carbon:windy-strong","carbon:winter-warning","carbon:wintry-mix","carbon:wireless-checkout","carbon:wmv","carbon:word-cloud","carbon:workflow-automation","carbon:workspace","carbon:workspace-import","carbon:worship","carbon:worship-christian","carbon:worship-jewish","carbon:worship-muslim","carbon:x","carbon:x-axis","carbon:xls","carbon:xml","carbon:y","carbon:y-axis","carbon:z","carbon:z-axis","carbon:z-lpar","carbon:z-systems","carbon:zip","carbon:zip-reference","carbon:zoom-area","carbon:zoom-fit","carbon:zoom-in","carbon:zoom-in-area","carbon:zoom-out","carbon:zoom-out-area","carbon:zoom-pan","carbon:zoom-reset","carbon:zos","carbon:zos-sysplex","fluent-mdl2:remove-from-trash","mdi:content-save","mdi:map-marker","ph:map-pin-fill","simple-icons:tiktok"] as const diff --git a/packages/ui/icon/index.tsx b/packages/ui/icon/index.tsx index 561b2ab2c8..4ca34f59e8 100644 --- a/packages/ui/icon/index.tsx +++ b/packages/ui/icon/index.tsx @@ -9,11 +9,13 @@ export const isValidIcon = (icon: unknown): icon is IconList => typeof icon === 'string' && iconList.includes(icon as IconList) export const validateIcon = (icon: unknown): IconList => { - if (isValidIcon(icon)) return icon + if (isValidIcon(icon)) { + return icon + } return 'carbon:unknown-filled' } -const useStyles = createStyles((theme, { block, color }: IconStylesParams) => ({ +const useStyles = createStyles((_theme, { block, color }: IconStylesParams) => ({ root: { display: block ? 'block' : undefined, color, @@ -23,7 +25,14 @@ const useStyles = createStyles((theme, { block, color }: IconStylesParams) => ({ export const Icon = memo(({ icon, block, className, ref, color, ...props }: CustomIconProps) => { const { classes, cx } = useStyles({ block, color }) Iconify.displayName = 'Iconify' - return + return ( + + ) }) Icon.displayName = '@weareinreach/ui/icon' @@ -40,3 +49,4 @@ interface CustomIconifyIconProps extends IconifyIconProps, IconStylesParams { type IconElementProps = SVGProps type CustomIconProps = IconElementProps & CustomIconifyIconProps & { ref?: Ref } +export { IconifyIconHTMLElement } diff --git a/packages/ui/mockData/fieldOpt.ts b/packages/ui/mockData/fieldOpt.ts index 7ac50baa08..f83763e8b9 100644 --- a/packages/ui/mockData/fieldOpt.ts +++ b/packages/ui/mockData/fieldOpt.ts @@ -57,6 +57,7 @@ const queryLanguages: MockAPIHandler<'fieldOpt', 'languages'> = async (query) => return activelyTranslated === record.activelyTranslated } } + return false }) } return languages @@ -77,13 +78,17 @@ const queryCountries: MockAPIHandler<'fieldOpt', 'countries'> = async (query) => const queryGovDistsByCountry: MockAPIHandler<'fieldOpt', 'govDistsByCountry'> = async (query) => { const govDistsByCountry = (await import('./json/fieldOpt.govDistsByCountry.json')).default - if (query) return govDistsByCountry.filter(({ cca2 }) => cca2 === query) + if (query) { + return govDistsByCountry.filter(({ cca2 }) => cca2 === query) + } return govDistsByCountry } const queryGovDistsByCountryNoSub: MockAPIHandler<'fieldOpt', 'govDistsByCountryNoSub'> = async (query) => { const govDistByCountryNoSub = (await import('./json/fieldOpt.govDistsByCountryNoSub.json')).default - if (query) return govDistByCountryNoSub.filter(({ cca2 }) => cca2 === query) + if (query) { + return govDistByCountryNoSub.filter(({ cca2 }) => cca2 === query) + } return govDistByCountryNoSub } @@ -146,13 +151,15 @@ const countryGovDistMapSchema = z .array() const countryGovDistMap = async () => { - const countryGovDistMapData = (await import('./json/fieldOpt.countryGovDistMap.json')).default + const { default: countryGovDistMapData } = (await import('./json/fieldOpt.countryGovDistMap.json')) as { + default: unknown + } return new Map(countryGovDistMapSchema.parse(countryGovDistMapData)) } const getSubDistricts: MockAPIHandler<'fieldOpt', 'getSubDistricts'> = async (id) => { const data = (await import('./json/fieldOpt.getSubDistricts.json')).default const filtered = data.filter(({ parentId }) => parentId === id) - const formatted = filtered.map(({ parentId, ...data }) => data) + const formatted = filtered.map(({ parentId: _parentId, ...rest }) => rest) return formatted } export const fieldOpt = { @@ -199,7 +206,7 @@ export const fieldOpt = { govDists: getTRPCMock({ path: ['fieldOpt', 'govDists'], response: async (input) => { - const data = (await import('./json/fieldOpt.govDists.json')).default + const data = (await import('./json/fieldOpt.govDists.json')).default as GovDistFieldOpts[] if (input) { const { parentsOnly, ...search } = input @@ -212,10 +219,10 @@ export const fieldOpt = { } return isMatch }) - const formatted = filtered.map(({ parentId, ...data }) => data) - return formatted + const formattedFiltered = filtered.map(({ parentId: _parentId, ...rest }) => rest) + return formattedFiltered } - const formatted = data.map(({ parentId, ...data }) => data) + const formatted = data.map(({ parentId: _parentId, ...rest }) => rest) return formatted }, }), @@ -262,3 +269,107 @@ interface CountryGovDistMapItem { children: CountryGovDistMapItemBasic[] parent?: CountryGovDistMapItemBasic & { parent?: CountryGovDistMapItemBasic } } + +export interface GovDistFieldOpts { + id: string + tsKey: string + tsNs: TsNS + abbrev: null | string + country: Country + govDistType: GovDistType + parentId: ParentID | null + name: string + slug: string + iso: null | string + countryId: CountryID +} + +export interface Country { + cca2: Cca2 +} + +export enum Cca2 { + CA = 'CA', + MX = 'MX', + PR = 'PR', + Us = 'US', +} + +export enum CountryID { + Ctry01GW2HHDK7PACTC9GJ2XBMVPKY = 'ctry_01GW2HHDK7PACTC9GJ2XBMVPKY', + Ctry01GW2HHDK9M26M80SG63T21SVH = 'ctry_01GW2HHDK9M26M80SG63T21SVH', + Ctry01GW2HHDKAWXWYHAAESAA5HH94 = 'ctry_01GW2HHDKAWXWYHAAESAA5HH94', + Ctry01GW2HHDKB9DG2T2YZM5MFFVX9 = 'ctry_01GW2HHDKB9DG2T2YZM5MFFVX9', +} + +export interface GovDistType { + tsKey: TsKey + tsNs: TsNS +} + +export enum TsKey { + TypeCity = 'type-city', + TypeCounty = 'type-county', + TypeDistrict = 'type-district', + TypeProvince = 'type-province', + TypeState = 'type-state', + TypeTerritory = 'type-territory', +} + +export enum TsNS { + GovDist = 'gov-dist', +} + +export enum ParentID { + Gdst01GW2HHY0735M7CQSXR31HP114 = 'gdst_01GW2HHY0735M7CQSXR31HP114', + Gdst01GW2HHZ3C061BT60QBAD8WVJZ = 'gdst_01GW2HHZ3C061BT60QBAD8WVJZ', + Gdst01GW2HJ0MERT6FW07XV7PZWZWE = 'gdst_01GW2HJ0MERT6FW07XV7PZWZWE', + Gdst01GW2HJ1D3W61ZMBGY0FGKY9EC = 'gdst_01GW2HJ1D3W61ZMBGY0FGKY9EC', + Gdst01GW2HJ23GMD17FBJMJWD16PZ1 = 'gdst_01GW2HJ23GMD17FBJMJWD16PZ1', + Gdst01GW2HJ35FAMD0V0YSSPYPMG46 = 'gdst_01GW2HJ35FAMD0V0YSSPYPMG46', + Gdst01GW2HJ48BS27DYW8W4GNH4P2W = 'gdst_01GW2HJ48BS27DYW8W4GNH4P2W', + Gdst01GW2HJ4XTJT4GBEWDBY057B01 = 'gdst_01GW2HJ4XTJT4GBEWDBY057B01', + Gdst01GW2HJ5A278S2G84AB3N9FCW0 = 'gdst_01GW2HJ5A278S2G84AB3N9FCW0', + Gdst01GW2HJ5XJRY6B6JNVZ8G8NFJY = 'gdst_01GW2HJ5XJRY6B6JNVZ8G8NFJY', + Gdst01GW2HJ6WC0EDHHCHG998QT3N0 = 'gdst_01GW2HJ6WC0EDHHCHG998QT3N0', + Gdst01GW2HJ7VX37RF69KKXAYE05QN = 'gdst_01GW2HJ7VX37RF69KKXAYE05QN', + Gdst01GW2HJ8HJJWY8F1GKEM5R8QZ4 = 'gdst_01GW2HJ8HJJWY8F1GKEM5R8QZ4', + Gdst01GW2HJ9GVN301XN2SKRWE8Q3M = 'gdst_01GW2HJ9GVN301XN2SKRWE8Q3M', + Gdst01GW2HJAD7VVT46D0BHXQRV2WF = 'gdst_01GW2HJAD7VVT46D0BHXQRV2WF', + Gdst01GW2HJC4WJWMZA8VDNVVE5RZQ = 'gdst_01GW2HJC4WJWMZA8VDNVVE5RZQ', + Gdst01GW2HJDE344VFWCSNBYYSFDDW = 'gdst_01GW2HJDE344VFWCSNBYYSFDDW', + Gdst01GW2HJF2WCKZ47HGSYQFANCDZ = 'gdst_01GW2HJF2WCKZ47HGSYQFANCDZ', + Gdst01GW2HJG2676AX4NRXHWA4PB8B = 'gdst_01GW2HJG2676AX4NRXHWA4PB8B', + Gdst01GW2HJH13NCXACKZGG242PM97 = 'gdst_01GW2HJH13NCXACKZGG242PM97', + Gdst01GW2HJHQBKA67H0WWG35J4PV7 = 'gdst_01GW2HJHQBKA67H0WWG35J4PV7', + Gdst01GW2HJJGA979WFBS7S7ECK0JK = 'gdst_01GW2HJJGA979WFBS7S7ECK0JK', + Gdst01GW2HJK994XZPC3KNCPVST015 = 'gdst_01GW2HJK994XZPC3KNCPVST015', + Gdst01GW2HJMBQGM1ZDVR1TJX4N6DY = 'gdst_01GW2HJMBQGM1ZDVR1TJX4N6DY', + Gdst01GW2HJMYCBT3EWB9XCX2VSMK9 = 'gdst_01GW2HJMYCBT3EWB9XCX2VSMK9', + Gdst01GW2HJPZYX059W3SHQW8D9F7M = 'gdst_01GW2HJPZYX059W3SHQW8D9F7M', + Gdst01GW2HJQZ5J517QW02C84M80WD = 'gdst_01GW2HJQZ5J517QW02C84M80WD', + Gdst01GW2HJRVH0VX93NDHEJ0QK158 = 'gdst_01GW2HJRVH0VX93NDHEJ0QK158', + Gdst01GW2HJSQZ19Y230FJHNKHSW89 = 'gdst_01GW2HJSQZ19Y230FJHNKHSW89', + Gdst01GW2HJTSK0AMAVYF9QD9GXBAR = 'gdst_01GW2HJTSK0AMAVYF9QD9GXBAR', + Gdst01GW2HJVFHMQEZZ1AKH9QETVP6 = 'gdst_01GW2HJVFHMQEZZ1AKH9QETVP6', + Gdst01GW2HJW29RXPB0ZW6ZTTPH7DY = 'gdst_01GW2HJW29RXPB0ZW6ZTTPH7DY', + Gdst01GW2HJXH936VB5WWAHK8S8X0A = 'gdst_01GW2HJXH936VB5WWAHK8S8X0A', + Gdst01GW2HJY7KQKE8XCP6BM8WC459 = 'gdst_01GW2HJY7KQKE8XCP6BM8WC459', + Gdst01GW2HJZG4VMQ7QWQ3MHXG3S8K = 'gdst_01GW2HJZG4VMQ7QWQ3MHXG3S8K', + Gdst01GW2HK0N4V9YBGBSQVN4JRKKW = 'gdst_01GW2HK0N4V9YBGBSQVN4JRKKW', + Gdst01GW2HK1MBAAXAR655YEESJRB1 = 'gdst_01GW2HK1MBAAXAR655YEESJRB1', + Gdst01GW2HK2PW0GCZATZ6YX9RG8FE = 'gdst_01GW2HK2PW0GCZATZ6YX9RG8FE', + Gdst01GW2HK3G7JGSCMVRQERYCRQGY = 'gdst_01GW2HK3G7JGSCMVRQERYCRQGY', + Gdst01GW2HK49A5XQ8ZDFKQSF098SJ = 'gdst_01GW2HK49A5XQ8ZDFKQSF098SJ', + Gdst01GW2HK51XDFN3Q0ND2NCGBN14 = 'gdst_01GW2HK51XDFN3Q0ND2NCGBN14', + Gdst01GW2HK5R9S8ZRWG9Z3BPFAXND = 'gdst_01GW2HK5R9S8ZRWG9Z3BPFAXND', + Gdst01GW2HK6H7B5T82KZ82DZSFNR0 = 'gdst_01GW2HK6H7B5T82KZ82DZSFNR0', + Gdst01GW2HK7G3WV9NP68CJ02WPMV7 = 'gdst_01GW2HK7G3WV9NP68CJ02WPMV7', + Gdst01GW2HK8W4ZDJSZDPWZH2XH023 = 'gdst_01GW2HK8W4ZDJSZDPWZH2XH023', + Gdst01GW2HK9J2HNR9ZCJJHF8WAGDT = 'gdst_01GW2HK9J2HNR9ZCJJHF8WAGDT', + Gdst01GW2HKADSS3SDS9XJV1WHMTVY = 'gdst_01GW2HKADSS3SDS9XJV1WHMTVY', + Gdst01GW2HKC6JBVM1S4P89T664V0A = 'gdst_01GW2HKC6JBVM1S4P89T664V0A', + Gdst01GW2HKD240CAP65TPYPT32MRR = 'gdst_01GW2HKD240CAP65TPYPT32MRR', + Gdst01GW2HKDJ5VV91D7JP3V6DE3DK = 'gdst_01GW2HKDJ5VV91D7JP3V6DE3DK', + Gdst01GW2HKEDZ2K9QXJ96SKR44EGV = 'gdst_01GW2HKEDZ2K9QXJ96SKR44EGV', +} diff --git a/packages/ui/mockData/orgPhone.ts b/packages/ui/mockData/orgPhone.ts index 8cc9bb2d45..6ddf00146d 100644 --- a/packages/ui/mockData/orgPhone.ts +++ b/packages/ui/mockData/orgPhone.ts @@ -8,11 +8,6 @@ export const orgPhone = { return data }, }), - upsertMany: getTRPCMock({ - path: ['orgPhone', 'upsertMany'], - type: 'mutation', - response: () => [], - }), update: getTRPCMock({ path: ['orgPhone', 'update'], type: 'mutation', diff --git a/packages/ui/modals/ModalTitle.tsx b/packages/ui/modals/ModalTitle.tsx index c44ef17131..8586acdedc 100644 --- a/packages/ui/modals/ModalTitle.tsx +++ b/packages/ui/modals/ModalTitle.tsx @@ -5,15 +5,22 @@ import { ActionButtons } from '~ui/components/core/ActionButtons' import { Breadcrumb, type BreadcrumbProps, isValidBreadcrumbProps } from '~ui/components/core/Breadcrumb' import { useCustomVariant } from '~ui/hooks' -export const ModalTitle = (props: ModalTitleProps) => { +export const ModalTitle = (props: _ModalTitleProps) => { const { breadcrumb, icons, rightText, serviceId } = props const variants = useCustomVariant() if (!isValidBreadcrumbProps(breadcrumb)) { throw new Error('invalid Breadcrumb props') } const iconMap = { - save: , - share: , + save: ( + + ), + share: , } as const const displayIcons = icons?.length ? icons.map((item) => iconMap[item]) : undefined @@ -43,11 +50,14 @@ export const ModalTitle = (props: ModalTitleProps) => { // type TitleIcons = keyof typeof iconMap -export type ModalTitleProps = { +type ToolbarIcons = 'save' | 'share' + +type _ModalTitleProps = { breadcrumb: Omit & { onClick: MouseEventHandler | (() => void) } - icons?: ('save' | 'share')[] + icons?: TIcons rightText?: string - serviceId?: string + serviceId?: 'save' extends TIcons[number] ? string : never } +export type ModalTitleProps = _ModalTitleProps diff --git a/packages/ui/modals/QuickPromotion.tsx b/packages/ui/modals/QuickPromotion.tsx index 55bd84d555..7a8180913b 100644 --- a/packages/ui/modals/QuickPromotion.tsx +++ b/packages/ui/modals/QuickPromotion.tsx @@ -1,13 +1,4 @@ -import { - Box, - type ButtonProps, - createPolymorphicComponent, - Group, - Modal, - Stack, - Text, - Title, -} from '@mantine/core' +import { Box, createPolymorphicComponent, Group, Modal, Stack, Text, Title } from '@mantine/core' import { useDisclosure } from '@mantine/hooks' import { useRouter } from 'next/router' import { useSession } from 'next-auth/react' @@ -15,7 +6,7 @@ import { Trans, useTranslation } from 'next-i18next' import { forwardRef, type MouseEventHandler, useCallback, useEffect, useMemo } from 'react' import { Breadcrumb, type BreadcrumbProps } from '~ui/components/core/Breadcrumb' -import { Button } from '~ui/components/core/Button' +import { Button, type ButtonProps } from '~ui/components/core/Button' import { Link } from '~ui/components/core/Link' import { useCustomVariant, useScreenSize } from '~ui/hooks' @@ -115,14 +106,14 @@ const QuickPromotionModalBody = forwardRef{t('dont-have-account')} - {!autoLaunch && } + {!autoLaunch && } ) } ) QuickPromotionModalBody.displayName = 'QuickPromotionModal' -export const QuickPromotionModal = createPolymorphicComponent<'button', QuickPromotionModalProps>( +export const QuickPromotionModal = createPolymorphicComponent( QuickPromotionModalBody ) diff --git a/packages/ui/modals/Review.tsx b/packages/ui/modals/Review.tsx index 251f905785..3f687561a8 100644 --- a/packages/ui/modals/Review.tsx +++ b/packages/ui/modals/Review.tsx @@ -1,8 +1,9 @@ -import { Box, type ButtonProps, createPolymorphicComponent, Group, Modal } from '@mantine/core' +import { Box, createPolymorphicComponent, Group, Modal } from '@mantine/core' import { useDisclosure } from '@mantine/hooks' import { forwardRef } from 'react' import { Breadcrumb } from '~ui/components/core/Breadcrumb' +import { Button, type ButtonProps } from '~ui/components/core/Button' import { UserReviewSubmit } from '~ui/components/core/UserReviewSubmit' import { useScreenSize } from '~ui/hooks/useScreenSize' @@ -22,13 +23,13 @@ const ReviewModalBody = forwardRef((props, - + ) }) ReviewModalBody.displayName = 'ReviewModal' -export const ReviewModal = createPolymorphicComponent<'button', ReviewModalProps>(ReviewModalBody) +export const ReviewModal = createPolymorphicComponent(ReviewModalBody) export type ReviewModalProps = ButtonProps diff --git a/packages/ui/theme/common.tsx b/packages/ui/theme/common.tsx index f143c860aa..0480f94ae7 100644 --- a/packages/ui/theme/common.tsx +++ b/packages/ui/theme/common.tsx @@ -120,10 +120,10 @@ const themeCustomObj = { border: { default: '1px solid #d9d9d9', }, - colors, animations: { shake, }, + colors, } as const //satisfies MantineThemeOther export const commonTheme = { @@ -655,7 +655,7 @@ export const commonTheme = { ({ radius: 'xl', }) satisfies SkeletonProps, - styles: (theme, { circle }: SkeletonStylesParams) => + styles: (_theme, { circle }: SkeletonStylesParams) => ({ root: { minWidth: circle ? undefined : rem(100),