-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(sanctionCheck): display enrich button and new fields for matches (…
…#733) * feat(sanctionCheck): display enrich button and new fields for matches * add success/error management
- Loading branch information
1 parent
3410108
commit 6f93625
Showing
17 changed files
with
434 additions
and
107 deletions.
There are no files selected for viewing
100 changes: 100 additions & 0 deletions
100
packages/app-builder/src/components/Sanctions/EntityProperties.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { | ||
createPropertyTransformer, | ||
getSanctionEntityProperties, | ||
type PropertyForSchema, | ||
type SanctionCheckEntityProperty, | ||
} from '@app-builder/constants/sanction-check-entity'; | ||
import { type OpenSanctionEntity } from '@app-builder/models/sanction-check'; | ||
import { useFormatLanguage } from '@app-builder/utils/format'; | ||
import { Fragment, type ReactNode, useMemo, useState } from 'react'; | ||
import { useTranslation } from 'react-i18next'; | ||
|
||
import { sanctionsI18n } from './sanctions-i18n'; | ||
|
||
export function EntityProperties<T extends OpenSanctionEntity>({ | ||
entity, | ||
forcedProperties, | ||
showUnavailable = false, | ||
before, | ||
after, | ||
}: { | ||
entity: T; | ||
forcedProperties?: PropertyForSchema<T['schema']>[]; | ||
showUnavailable?: boolean; | ||
before?: ReactNode; | ||
after?: ReactNode; | ||
}) { | ||
const [displayAll, setDisplayAll] = useState< | ||
Partial<Record<SanctionCheckEntityProperty, boolean>> | ||
>({}); | ||
|
||
const displayProperties = forcedProperties ?? getSanctionEntityProperties(entity.schema); | ||
const { t, i18n } = useTranslation(sanctionsI18n); | ||
const language = useFormatLanguage(); | ||
const entityPropertyList = displayProperties | ||
.map((property) => { | ||
const items = entity.properties[property] ?? []; | ||
const itemsToDisplay = displayAll[property] ? items : items.slice(0, 5); | ||
return { | ||
property, | ||
values: itemsToDisplay, | ||
restItemsCount: Math.max(0, items.length - itemsToDisplay.length), | ||
}; | ||
}) | ||
.filter((prop) => (showUnavailable ? true : prop.values.length > 0)); | ||
|
||
const TransformProperty = useMemo( | ||
() => | ||
createPropertyTransformer({ | ||
language: i18n.language, | ||
formatLanguage: language, | ||
}), | ||
[i18n.language, language], | ||
); | ||
|
||
const handleShowMore = (prop: string) => { | ||
setDisplayAll((prev) => ({ ...prev, [prop]: true })); | ||
}; | ||
|
||
return ( | ||
<div className="grid grid-cols-[168px,_1fr] gap-2"> | ||
{before} | ||
{entityPropertyList.map(({ property, values, restItemsCount }) => { | ||
return ( | ||
<Fragment key={property}> | ||
<span className="font-bold">{t(`sanctions:entity.property.${property}`)}</span> | ||
<span className="break-all"> | ||
{values.length > 0 ? ( | ||
<> | ||
{values.map((v, i) => ( | ||
<Fragment key={i}> | ||
<TransformProperty property={property} value={v} /> | ||
{i === values.length - 1 ? null : <span className="mx-1">·</span>} | ||
</Fragment> | ||
))} | ||
{restItemsCount > 0 ? ( | ||
<> | ||
<span className="mx-1">·</span> | ||
<button | ||
onClick={(e) => { | ||
e.preventDefault(); | ||
handleShowMore(property); | ||
}} | ||
className="text-purple-65 font-semibold" | ||
> | ||
+ {restItemsCount} more | ||
</button> | ||
</> | ||
) : null} | ||
</> | ||
) : ( | ||
<span className="text-grey-50">not available</span> | ||
)} | ||
</span> | ||
</Fragment> | ||
); | ||
})} | ||
{after} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
132 changes: 66 additions & 66 deletions
132
packages/app-builder/src/components/Sanctions/MatchDetails.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,83 +1,83 @@ | ||
import { type PropertyForSchema } from '@app-builder/constants/sanction-check-entity'; | ||
import { | ||
createPropertyTransformer, | ||
getSanctionEntityProperties, | ||
type SanctionCheckEntityProperty, | ||
} from '@app-builder/constants/sanction-check-entity'; | ||
import { type SanctionCheckMatch } from '@app-builder/models/sanction-check'; | ||
import { useFormatLanguage } from '@app-builder/utils/format'; | ||
import { Fragment, useMemo, useState } from 'react'; | ||
type SanctionCheckMatch, | ||
type SanctionCheckSanctionEntity, | ||
} from '@app-builder/models/sanction-check'; | ||
import { useState } from 'react'; | ||
import { useTranslation } from 'react-i18next'; | ||
import { ModalV2 } from 'ui-design-system'; | ||
import { Icon } from 'ui-icons'; | ||
|
||
import { EntityProperties } from './EntityProperties'; | ||
import { sanctionsI18n } from './sanctions-i18n'; | ||
|
||
export type MatchDetailsProps = { | ||
entity: SanctionCheckMatch['payload']; | ||
}; | ||
|
||
export function MatchDetails({ entity }: MatchDetailsProps) { | ||
const { t, i18n } = useTranslation(sanctionsI18n); | ||
const language = useFormatLanguage(); | ||
const [displayAll, setDisplayAll] = useState< | ||
Partial<Record<SanctionCheckEntityProperty, boolean>> | ||
>({}); | ||
const sanctionProps = [ | ||
'country', | ||
'authority', | ||
'authorityId', | ||
'startDate', | ||
'endDate', | ||
'listingDate', | ||
'program', | ||
'programId', | ||
'programUrl', | ||
'summary', | ||
'reason', | ||
'sourceUrl', | ||
] satisfies PropertyForSchema<'Sanction'>[]; | ||
|
||
const TransformProperty = useMemo( | ||
() => | ||
createPropertyTransformer({ | ||
language: i18n.language, | ||
formatLanguage: language, | ||
}), | ||
[i18n.language, language], | ||
export function MatchDetails({ entity }: MatchDetailsProps) { | ||
const { t } = useTranslation(sanctionsI18n); | ||
const [selectedSanction, setSelectedSanction] = useState<SanctionCheckSanctionEntity | null>( | ||
null, | ||
); | ||
|
||
const displayProperties = getSanctionEntityProperties(entity.schema); | ||
const entityPropertyList = displayProperties | ||
.map((property) => { | ||
const items = entity.properties[property] ?? []; | ||
const itemsToDisplay = displayAll[property] ? items : items.slice(0, 5); | ||
return { | ||
property, | ||
values: itemsToDisplay, | ||
restItemsCount: Math.max(0, items.length - itemsToDisplay.length), | ||
}; | ||
}) | ||
.filter((prop) => prop.values.length > 0); | ||
|
||
const handleShowMore = (prop: string) => { | ||
setDisplayAll((prev) => ({ ...prev, [prop]: true })); | ||
}; | ||
|
||
return ( | ||
<div className="grid grid-cols-[168px,_1fr] gap-2"> | ||
{entityPropertyList.map(({ property, values, restItemsCount }) => { | ||
return ( | ||
<Fragment key={property}> | ||
<span className="font-bold">{t(`sanctions:entity.property.${property}`)}</span> | ||
<span className="flex flex-wrap gap-1 break-all"> | ||
{values.map((v, i) => ( | ||
<Fragment key={i}> | ||
<TransformProperty property={property} value={v} /> | ||
{i === values.length - 1 ? null : <span>·</span>} | ||
</Fragment> | ||
))} | ||
{restItemsCount > 0 ? ( | ||
<> | ||
<span>·</span> | ||
<button | ||
onClick={(e) => { | ||
e.preventDefault(); | ||
handleShowMore(property); | ||
}} | ||
className="text-purple-65 font-semibold" | ||
<div className="flex flex-col gap-4"> | ||
<EntityProperties | ||
entity={entity} | ||
after={ | ||
entity.properties.sanctions ? ( | ||
<> | ||
<span className="font-bold">{t('sanctions:entity.property.sanctions')}</span> | ||
<div className="flex flex-col gap-2"> | ||
{entity.properties.sanctions.map((sanction) => ( | ||
<div | ||
key={sanction.id} | ||
className="group/sanction bg-grey-100 grid grid-cols-[1fr_20px] gap-2 rounded p-2" | ||
> | ||
+ {restItemsCount} more | ||
</button> | ||
</> | ||
) : null} | ||
</span> | ||
</Fragment> | ||
); | ||
})} | ||
<span className="truncate">{sanction.properties['authority']}</span> | ||
<button type="button" onClick={() => setSelectedSanction(sanction)}> | ||
<Icon | ||
icon="visibility-on" | ||
className="text-grey-90 hover:text-purple-65 size-5 cursor-pointer" | ||
/> | ||
</button> | ||
</div> | ||
))} | ||
</div> | ||
|
||
<ModalV2.Content | ||
open={!!selectedSanction} | ||
onClose={() => setSelectedSanction(null)} | ||
size="large" | ||
className="max-h-[80vh]" | ||
> | ||
<ModalV2.Title>{t('sanctions:sanction_detail.title')}</ModalV2.Title> | ||
<div className="overflow-y-auto p-6"> | ||
{selectedSanction ? ( | ||
<EntityProperties entity={selectedSanction} forcedProperties={sanctionProps} /> | ||
) : null} | ||
</div> | ||
</ModalV2.Content> | ||
</> | ||
) : null | ||
} | ||
/> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.