Skip to content

Commit 801566a

Browse files
authored
Adjust date override conflict to handle partnerships (#1659)
1 parent c7556b6 commit 801566a

File tree

2 files changed

+59
-27
lines changed

2 files changed

+59
-27
lines changed

src/api/errorHandling/error.types.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { ApolloError } from '@apollo/client';
22
import { assert } from 'ts-essentials';
3+
import { IdFragment } from '~/common';
34
import { GqlTypeMapMain } from '../schema';
4-
import { ProductStep, Project } from '../schema.graphql';
5+
import { ProductStep } from '../schema.graphql';
56

67
interface CordErrorExtensions {
78
codes: readonly Code[];
@@ -28,7 +29,7 @@ export interface ErrorMap {
2829
Unauthorized: InputError;
2930
MissingRequiredFields: MissingRequiredFieldsError;
3031
StepNotPlanned: StepNotPlannedError;
31-
EngagementDateOverrideConflict: EngagementDateOverrideConflictError;
32+
DateOverrideConflict: DateOverrideConflictError;
3233

3334
/**
3435
* This is a special one that allows a default handler for any
@@ -105,10 +106,12 @@ export interface StepNotPlannedError extends InputError {
105106
index: number;
106107
}
107108

108-
export interface EngagementDateOverrideConflictError extends InputError {
109-
readonly project: Pick<Project, 'id' | 'name' | 'mouStart' | 'mouEnd'>;
110-
readonly engagements: ReadonlyArray<
109+
export interface DateOverrideConflictError extends InputError {
110+
readonly object: IdFragment;
111+
readonly canonical: Record<'start' | 'end', string | null>;
112+
readonly conflicts: ReadonlyArray<
111113
Readonly<{
114+
__typename: keyof GqlTypeMapMain;
112115
id: string;
113116
label: string;
114117
point: 'start' | 'end';

src/scenes/Projects/Update/UpdateProjectDialog.tsx

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useMutation } from '@apollo/client';
2-
import { Box, Typography } from '@mui/material';
3-
import { many, Many } from '@seedcompany/common';
2+
import { Box, Stack, Typography } from '@mui/material';
3+
import { groupBy, many, Many } from '@seedcompany/common';
44
import { FORM_ERROR } from 'final-form';
55
import { pick } from 'lodash';
66
import { ComponentType, useMemo } from 'react';
@@ -225,28 +225,57 @@ export const UpdateProjectDialog = ({
225225
});
226226
}}
227227
errorHandlers={{
228-
EngagementDateOverrideConflict: ({ engagements }) => {
228+
DateOverrideConflict: ({ conflicts, object }) => {
229229
const rendered = (
230-
<>
231-
<Typography variant="body2" gutterBottom>
232-
{engagements.length === 1
233-
? 'An engagement has a date outside the new range'
234-
: 'Some engagements have dates outside the new range'}
235-
</Typography>
236-
<Box component="ul" sx={{ m: 0, paddingInlineStart: 4 }}>
237-
{engagements.map((eng) => (
238-
<li key={eng.id + eng.point}>
239-
{eng.point === 'start' ? 'Start' : 'End'} date of{' '}
240-
<Link to={`/engagements/${eng.id}`} color="inherit">
241-
{eng.label}
242-
</Link>{' '}
243-
is <FormattedDate date={CalendarDate.fromISO(eng.date)} />
244-
</li>
245-
))}
246-
</Box>
247-
</>
230+
<Stack gap={2}>
231+
{groupBy(conflicts, (conflict) => conflict.__typename).map(
232+
(conflicts) => {
233+
const type = conflicts[0].__typename;
234+
const labels =
235+
type === 'Partnership'
236+
? (['A partnership', 'Some partnerships'] as const)
237+
: type.endsWith('Engagement')
238+
? (['An engagement', 'Some engagements'] as const)
239+
: (['An object', 'Some objects'] as const);
240+
const getUrl =
241+
type === 'Partnership'
242+
? () => `/projects/${object.id}/partnerships`
243+
: type.endsWith('Engagement')
244+
? (id: string) => `/engagements/${id}`
245+
: null;
246+
return (
247+
<div key={type}>
248+
<Typography variant="body2" gutterBottom>
249+
{conflicts.length === 1
250+
? `${labels[0]} has a date outside the new range`
251+
: `${labels[1]} have dates outside the new range`}
252+
</Typography>
253+
<Box component="ul" sx={{ m: 0, paddingInlineStart: 4 }}>
254+
{conflicts.map((conflict) => (
255+
<li key={conflict.id + conflict.point}>
256+
{conflict.point === 'start' ? 'Start' : 'End'} date
257+
of{' '}
258+
{getUrl ? (
259+
<Link to={getUrl(conflict.id)} color="inherit">
260+
{conflict.label}
261+
</Link>
262+
) : (
263+
conflict.label
264+
)}{' '}
265+
is{' '}
266+
<FormattedDate
267+
date={CalendarDate.fromISO(conflict.date)}
268+
/>
269+
</li>
270+
))}
271+
</Box>
272+
</div>
273+
);
274+
}
275+
)}
276+
</Stack>
248277
);
249-
const points = new Set(engagements.map((eng) => eng.point));
278+
const points = new Set(conflicts.map((conflict) => conflict.point));
250279
return {
251280
[FORM_ERROR]: rendered,
252281
// Mark the field(s) as invalid,

0 commit comments

Comments
 (0)