Skip to content

Commit dc67792

Browse files
committed
reafactor: improve dx on case information form
1 parent f0a4576 commit dc67792

File tree

11 files changed

+274
-448
lines changed

11 files changed

+274
-448
lines changed

packages/app-builder/src/components/Cases/CaseHistory/CaseEvents.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
type RuleSnoozeCreatedEvent,
1111
} from '@app-builder/models/cases';
1212
import { useGetRuleSnoozeFetcher } from '@app-builder/routes/ressources+/rule-snoozes+/read.$ruleSnoozeId';
13+
import { useOrganizationTags } from '@app-builder/services/organization/organization-tags';
1314
import { useOrganizationUsers } from '@app-builder/services/organization/organization-users';
1415
import { getFullName } from '@app-builder/services/user';
1516
import { formatDateRelative, formatDateTime, useFormatLanguage } from '@app-builder/utils/format';
@@ -329,6 +330,7 @@ function DecisionReviewedEventDetail({ event }: { event: DecisionReviewedEvent }
329330

330331
function TagsUpdatedEventDetail({ event }: { event: CaseTagsUpdatedEvent }) {
331332
const { t } = useTranslation(casesI18n);
333+
const { orgTags } = useOrganizationTags();
332334
return (
333335
<div className="flex flex-col gap-2">
334336
<Author userId={event.userId} type="edited_by" />
@@ -342,7 +344,7 @@ function TagsUpdatedEventDetail({ event }: { event: CaseTagsUpdatedEvent }) {
342344
t={t}
343345
i18nKey="cases:case_detail.history.event_detail.case_tags.new"
344346
components={{
345-
CaseTags: <CaseTags caseTagIds={event.tagIds} />,
347+
CaseTags: <CaseTags caseTagIds={event.tagIds} orgTags={orgTags} />,
346348
}}
347349
/>
348350
</div>
Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,27 @@
1-
import { useOrganizationTags } from '@app-builder/services/organization/organization-tags';
21
import { type Tag } from 'marble-api';
32
import { matchSorter } from 'match-sorter';
43
import * as React from 'react';
54
import { useTranslation } from 'react-i18next';
6-
import { Input, Tooltip } from 'ui-design-system';
5+
import { Input, SelectWithCombobox, Tooltip } from 'ui-design-system';
76

8-
import { FormSelectWithCombobox } from '../Form/FormSelectWithCombobox';
97
import { casesI18n } from './cases-i18n';
108

11-
export function CaseTags({ caseTagIds }: { caseTagIds: string[] }) {
9+
export function CaseTags({ caseTagIds, orgTags }: { caseTagIds: string[]; orgTags: Tag[] }) {
1210
const { t } = useTranslation(casesI18n);
11+
1312
return (
1413
<Tooltip.Default
1514
content={
1615
<div className="flex max-w-sm flex-wrap gap-1">
1716
{caseTagIds.map((caseTagId) => (
18-
<CaseTag key={caseTagId} tagId={caseTagId} />
17+
<CaseTag key={caseTagId} tag={orgTags.find((t) => t.id === caseTagId)} />
1918
))}
2019
</div>
2120
}
2221
>
2322
<div className="flex w-fit flex-wrap items-center gap-1">
2423
{caseTagIds.slice(0, 3).map((caseTagId) => (
25-
<CaseTag key={caseTagId} tagId={caseTagId} />
24+
<CaseTag key={caseTagId} tag={orgTags.find((t) => t.id === caseTagId)} />
2625
))}
2726
{caseTagIds.length > 3 ? (
2827
<div className="text-grey-00 bg-grey-95 flex h-6 items-center rounded-s px-2 text-xs font-normal">
@@ -36,12 +35,9 @@ export function CaseTags({ caseTagIds }: { caseTagIds: string[] }) {
3635
);
3736
}
3837

39-
export function CaseTag({ tagId }: { tagId: string }) {
40-
const { getTagById } = useOrganizationTags();
38+
export function CaseTag({ tag }: { tag?: Tag }) {
4139
const { t } = useTranslation(casesI18n);
4240

43-
const tag = getTagById(tagId);
44-
4541
return (
4642
<div
4743
className="bg-grey-95 flex h-6 items-center rounded px-2"
@@ -54,14 +50,16 @@ export function CaseTag({ tagId }: { tagId: string }) {
5450
);
5551
}
5652

57-
export function FormSelectCaseTags({
58-
selectedTagIds,
53+
export function SelectCaseTags({
54+
name,
5955
orgTags,
60-
onOpenChange,
56+
selectedTagIds,
57+
onChange,
6158
}: {
62-
selectedTagIds: string[];
59+
name?: string;
6360
orgTags: Tag[];
64-
onOpenChange?: (open: boolean) => void;
61+
selectedTagIds: string[];
62+
onChange?: (value: string[]) => void;
6563
}) {
6664
const { t } = useTranslation(['cases']);
6765
const [searchValue, setSearchValue] = React.useState('');
@@ -73,35 +71,31 @@ export function FormSelectCaseTags({
7371
);
7472

7573
return (
76-
<FormSelectWithCombobox.Root
74+
<SelectWithCombobox.Root
7775
selectedValue={selectedTagIds}
7876
searchValue={searchValue}
7977
onSearchValueChange={setSearchValue}
80-
onOpenChange={onOpenChange}
78+
onSelectedValueChange={onChange}
8179
>
82-
<FormSelectWithCombobox.Select className="w-full">
83-
<CaseTags caseTagIds={selectedTagIds} />
84-
<FormSelectWithCombobox.Arrow />
85-
</FormSelectWithCombobox.Select>
86-
<FormSelectWithCombobox.Popover className="z-50 flex flex-col gap-2 p-2">
87-
<FormSelectWithCombobox.Combobox
88-
render={<Input className="shrink-0" />}
89-
autoSelect
90-
autoFocus
91-
/>
92-
<FormSelectWithCombobox.ComboboxList>
80+
<SelectWithCombobox.Select name={name} className="w-full">
81+
<CaseTags caseTagIds={selectedTagIds} orgTags={orgTags} />
82+
<SelectWithCombobox.Arrow />
83+
</SelectWithCombobox.Select>
84+
<SelectWithCombobox.Popover className="z-50 flex flex-col gap-2 p-2">
85+
<SelectWithCombobox.Combobox render={<Input className="shrink-0" />} autoSelect autoFocus />
86+
<SelectWithCombobox.ComboboxList>
9387
{matches.map((tag) => (
94-
<FormSelectWithCombobox.ComboboxItem key={tag.id} value={tag.id}>
95-
<CaseTag tagId={tag.id} />
96-
</FormSelectWithCombobox.ComboboxItem>
88+
<SelectWithCombobox.ComboboxItem key={tag.id} value={tag.id}>
89+
<CaseTag tag={tag} />
90+
</SelectWithCombobox.ComboboxItem>
9791
))}
9892
{matches.length === 0 ? (
9993
<p className="text-grey-50 flex items-center justify-center p-2">
10094
{t('cases:case_detail.tags.empty_matches')}
10195
</p>
10296
) : null}
103-
</FormSelectWithCombobox.ComboboxList>
104-
</FormSelectWithCombobox.Popover>
105-
</FormSelectWithCombobox.Root>
97+
</SelectWithCombobox.ComboboxList>
98+
</SelectWithCombobox.Popover>
99+
</SelectWithCombobox.Root>
106100
);
107101
}

packages/app-builder/src/components/Cases/CasesList.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { type Case } from '@app-builder/models/cases';
2+
import { useOrganizationTags } from '@app-builder/services/organization/organization-tags';
23
import { formatDateTime, useFormatLanguage } from '@app-builder/utils/format';
34
import { getRoute } from '@app-builder/utils/routes';
45
import { fromUUID } from '@app-builder/utils/short-uuid';
@@ -28,6 +29,7 @@ export function CasesList({
2829
const { t } = useTranslation(casesI18n);
2930
const language = useFormatLanguage();
3031
const [sorting, setSorting] = useState<SortingState>([]);
32+
const { orgTags } = useOrganizationTags();
3133

3234
useEffect(() => {
3335
onSortingChange(sorting);
@@ -85,7 +87,7 @@ export function CasesList({
8587
enableSorting: false,
8688
cell: ({ getValue }) => (
8789
<div className="p-2">
88-
<CaseTags caseTagIds={getValue().map(({ tagId }) => tagId)} />
90+
<CaseTags caseTagIds={getValue().map(({ tagId }) => tagId)} orgTags={orgTags} />
8991
</div>
9092
),
9193
}),
@@ -98,7 +100,7 @@ export function CasesList({
98100
cell: ({ getValue }) => <CaseContributors contributors={getValue()} />,
99101
}),
100102
],
101-
[language, t],
103+
[language, t, orgTags],
102104
);
103105

104106
const { table, getBodyProps, rows, getContainerProps } = useVirtualTable({
Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,29 @@
11
import { casesI18n } from '@app-builder/components/Cases';
2-
import { CaseContributors } from '@app-builder/components/Cases/CaseContributors';
3-
import { EditCaseInbox } from '@app-builder/routes/ressources+/cases+/edit-inbox';
4-
import { EditCaseName } from '@app-builder/routes/ressources+/cases+/edit-name';
5-
import { EditCaseTags } from '@app-builder/routes/ressources+/cases+/edit-tags';
6-
import { formatDateTime, useFormatLanguage } from '@app-builder/utils/format';
2+
import { EditCase } from '@app-builder/routes/ressources+/cases+/edit';
3+
import { serverServices } from '@app-builder/services/init.server';
4+
import { getRoute } from '@app-builder/utils/routes';
5+
import { type LoaderFunctionArgs } from '@remix-run/node';
6+
import { useLoaderData } from '@remix-run/react';
77
import { type Namespace } from 'i18next';
8-
import { useTranslation } from 'react-i18next';
98

109
import { useCurrentCase } from './$caseId._layout';
1110

1211
export const handle = {
1312
i18n: ['common', 'navigation', ...casesI18n] satisfies Namespace,
1413
};
1514

15+
export async function loader({ request }: LoaderFunctionArgs) {
16+
const { authService } = serverServices;
17+
const { inbox } = await authService.isAuthenticated(request, {
18+
failureRedirect: getRoute('/sign-in'),
19+
});
20+
21+
return { inboxes: await inbox.listInboxes() };
22+
}
23+
1624
export default function CasePage() {
17-
const { t } = useTranslation(handle.i18n);
18-
const { caseDetail, inbox, user } = useCurrentCase();
19-
const language = useFormatLanguage();
25+
const { caseDetail } = useCurrentCase();
26+
const { inboxes } = useLoaderData<typeof loader>();
2027

21-
return (
22-
<div className="bg-grey-100 border-grey-90 grid grid-cols-[max-content_1fr] grid-rows-[repeat(5,_minmax(40px,_min-content))] items-center gap-2 rounded-lg border p-4 lg:p-6">
23-
<EditCaseName caseId={caseDetail.id} name={caseDetail.name} />
24-
<div className="text-s font-semibold first-letter:capitalize">{t('cases:case.date')}</div>
25-
<time dateTime={caseDetail.createdAt}>
26-
{formatDateTime(caseDetail.createdAt, {
27-
language,
28-
timeStyle: undefined,
29-
})}
30-
</time>
31-
<EditCaseInbox defaultInbox={inbox} caseId={caseDetail.id} />
32-
<EditCaseTags
33-
defaultCaseTagIds={caseDetail.tags.map(({ tagId }) => tagId)}
34-
caseId={caseDetail.id}
35-
user={user}
36-
/>
37-
<div className="text-s font-semibold first-letter:capitalize">
38-
{t('cases:case.contributors')}
39-
</div>
40-
<CaseContributors contributors={caseDetail.contributors} />
41-
</div>
42-
);
28+
return <EditCase detail={caseDetail} inboxes={inboxes} />;
4329
}

packages/app-builder/src/routes/ressources+/cases+/edit-inbox.tsx

Lines changed: 0 additions & 119 deletions
This file was deleted.

0 commit comments

Comments
 (0)