Add trust center files
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
228
apps/console/src/components/trustCenter/TrustCenterFilesCard.tsx
Normal file
228
apps/console/src/components/trustCenter/TrustCenterFilesCard.tsx
Normal file
@@ -0,0 +1,228 @@
|
||||
import { graphql } from "relay-runtime";
|
||||
import {
|
||||
Card,
|
||||
Button,
|
||||
Tr,
|
||||
Td,
|
||||
Table,
|
||||
Thead,
|
||||
Tbody,
|
||||
Th,
|
||||
IconChevronDown,
|
||||
Field,
|
||||
Option,
|
||||
Badge,
|
||||
IconPencil,
|
||||
IconTrashCan,
|
||||
IconArrowLink,
|
||||
} from "@probo/ui";
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import type { TrustCenterFilesCardFragment$key, TrustCenterFilesCardFragment$data } from "./__generated__/TrustCenterFilesCardFragment.graphql";
|
||||
import { useFragment } from "react-relay";
|
||||
import { useMemo, useState, useCallback, useEffect } from "react";
|
||||
import { sprintf, getTrustCenterVisibilityOptions } from "@probo/helpers";
|
||||
import { formatDate } from "@probo/helpers";
|
||||
import clsx from "clsx";
|
||||
|
||||
const trustCenterFileFragment = graphql`
|
||||
fragment TrustCenterFilesCardFragment on TrustCenterFile {
|
||||
id
|
||||
name
|
||||
category
|
||||
fileUrl
|
||||
trustCenterVisibility
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
`;
|
||||
|
||||
type Mutation<Params> = (p: {
|
||||
variables: {
|
||||
input: {
|
||||
id: string;
|
||||
trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC";
|
||||
} & Params;
|
||||
};
|
||||
}) => void;
|
||||
|
||||
type Props<Params> = {
|
||||
files: TrustCenterFilesCardFragment$key[];
|
||||
params: Params;
|
||||
disabled?: boolean;
|
||||
onChangeVisibility: Mutation<Params>;
|
||||
onEdit: (file: { id: string; name: string; category: string }) => void;
|
||||
onDelete: (id: string) => void;
|
||||
variant?: "card" | "table";
|
||||
};
|
||||
|
||||
export function TrustCenterFilesCard<Params>(props: Props<Params>) {
|
||||
const { __ } = useTranslate();
|
||||
const [limit, setLimit] = useState<number | null>(4);
|
||||
const files = useMemo(() => {
|
||||
return limit ? props.files.slice(0, limit) : props.files;
|
||||
}, [props.files, limit]);
|
||||
const showMoreButton = limit !== null && props.files.length > limit;
|
||||
const variant = props.variant ?? "table";
|
||||
|
||||
const onChangeVisibility = (fileId: string, trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC") => {
|
||||
props.onChangeVisibility({
|
||||
variables: {
|
||||
input: {
|
||||
id: fileId,
|
||||
trustCenterVisibility,
|
||||
...props.params,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const Wrapper = variant === "card" ? Card : "div";
|
||||
|
||||
return (
|
||||
<Wrapper padded className="space-y-[10px]">
|
||||
<Table className={clsx(variant === "card" && "bg-invert")}>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>{__("Name")}</Th>
|
||||
<Th>{__("Category")}</Th>
|
||||
<Th>{__("Upload Date")}</Th>
|
||||
<Th>{__("Visibility")}</Th>
|
||||
<Th></Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{files.length === 0 && (
|
||||
<Tr>
|
||||
<Td colSpan={5} className="text-center text-txt-secondary">
|
||||
{__("No files available")}
|
||||
</Td>
|
||||
</Tr>
|
||||
)}
|
||||
{files.map((fileFragmentRef, index) => (
|
||||
<FileRowWrapper
|
||||
key={index}
|
||||
fileFragmentRef={fileFragmentRef}
|
||||
onChangeVisibility={onChangeVisibility}
|
||||
onEdit={props.onEdit}
|
||||
onDelete={props.onDelete}
|
||||
disabled={props.disabled}
|
||||
/>
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
{showMoreButton && (
|
||||
<Button
|
||||
variant="tertiary"
|
||||
onClick={() => setLimit(null)}
|
||||
className="mt-3 mx-auto"
|
||||
icon={IconChevronDown}
|
||||
>
|
||||
{sprintf(__("Show %s more"), props.files.length - limit)}
|
||||
</Button>
|
||||
)}
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
function FileRowWrapper(props: {
|
||||
fileFragmentRef: TrustCenterFilesCardFragment$key;
|
||||
onChangeVisibility: (fileId: string, trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC") => void;
|
||||
onEdit: (file: { id: string; name: string; category: string }) => void;
|
||||
onDelete: (id: string) => void;
|
||||
disabled?: boolean;
|
||||
}) {
|
||||
const file = useFragment(trustCenterFileFragment, props.fileFragmentRef);
|
||||
return (
|
||||
<FileRow
|
||||
file={file}
|
||||
onChangeVisibility={props.onChangeVisibility}
|
||||
onEdit={props.onEdit}
|
||||
onDelete={props.onDelete}
|
||||
disabled={props.disabled}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function FileRow(props: {
|
||||
file: TrustCenterFilesCardFragment$data;
|
||||
onChangeVisibility: (fileId: string, trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC") => void;
|
||||
onEdit: (file: { id: string; name: string; category: string }) => void;
|
||||
onDelete: (id: string) => void;
|
||||
disabled?: boolean;
|
||||
}) {
|
||||
const file = props.file;
|
||||
const { __ } = useTranslate();
|
||||
const [optimisticValue, setOptimisticValue] = useState<string | null>(null);
|
||||
|
||||
const handleValueChange = useCallback((value: string | {}) => {
|
||||
const stringValue = typeof value === 'string' ? value : '';
|
||||
const typedValue = stringValue as "NONE" | "PRIVATE" | "PUBLIC";
|
||||
setOptimisticValue(typedValue);
|
||||
props.onChangeVisibility(file.id, typedValue);
|
||||
}, [file.id, props.onChangeVisibility]);
|
||||
|
||||
useEffect(() => {
|
||||
if (optimisticValue && file.trustCenterVisibility === optimisticValue) {
|
||||
setOptimisticValue(null);
|
||||
}
|
||||
}, [file.trustCenterVisibility, optimisticValue]);
|
||||
|
||||
const currentValue = optimisticValue || file.trustCenterVisibility;
|
||||
|
||||
const visibilityOptions = getTrustCenterVisibilityOptions(__);
|
||||
|
||||
return (
|
||||
<Tr>
|
||||
<Td>
|
||||
<div className="flex gap-4 items-center">
|
||||
{file.name}
|
||||
</div>
|
||||
</Td>
|
||||
<Td>{file.category}</Td>
|
||||
<Td>{formatDate(file.createdAt)}</Td>
|
||||
<Td noLink width={130} className="pr-0">
|
||||
<Field
|
||||
type="select"
|
||||
value={currentValue}
|
||||
onValueChange={handleValueChange}
|
||||
disabled={props.disabled}
|
||||
className="w-[105px]"
|
||||
>
|
||||
{visibilityOptions.map((option) => (
|
||||
<Option key={option.value} value={option.value}>
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<Badge variant={option.variant}>
|
||||
{option.label}
|
||||
</Badge>
|
||||
</div>
|
||||
</Option>
|
||||
))}
|
||||
</Field>
|
||||
</Td>
|
||||
<Td noLink width={120}>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant="secondary"
|
||||
icon={IconArrowLink}
|
||||
onClick={() => window.open(file.fileUrl, '_blank', 'noopener,noreferrer')}
|
||||
title={__("Download")}
|
||||
/>
|
||||
<Button
|
||||
variant="secondary"
|
||||
icon={IconPencil}
|
||||
onClick={() => props.onEdit({ id: file.id, name: file.name, category: file.category })}
|
||||
disabled={props.disabled}
|
||||
title={__("Edit")}
|
||||
/>
|
||||
<Button
|
||||
variant="secondary"
|
||||
icon={IconTrashCan}
|
||||
onClick={() => props.onDelete(file.id)}
|
||||
disabled={props.disabled}
|
||||
title={__("Delete")}
|
||||
/>
|
||||
</div>
|
||||
</Td>
|
||||
</Tr>
|
||||
);
|
||||
}
|
||||
91
apps/console/src/components/trustCenter/__generated__/TrustCenterFilesCardFragment.graphql.ts
generated
Normal file
91
apps/console/src/components/trustCenter/__generated__/TrustCenterFilesCardFragment.graphql.ts
generated
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* @generated SignedSource<<0defaaf1ce3544420e8fbd9c9f3af139>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ReaderFragment } from 'relay-runtime';
|
||||
export type TrustCenterVisibility = "NONE" | "PRIVATE" | "PUBLIC";
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type TrustCenterFilesCardFragment$data = {
|
||||
readonly category: string;
|
||||
readonly createdAt: any;
|
||||
readonly fileUrl: string;
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly trustCenterVisibility: TrustCenterVisibility;
|
||||
readonly updatedAt: any;
|
||||
readonly " $fragmentType": "TrustCenterFilesCardFragment";
|
||||
};
|
||||
export type TrustCenterFilesCardFragment$key = {
|
||||
readonly " $data"?: TrustCenterFilesCardFragment$data;
|
||||
readonly " $fragmentSpreads": FragmentRefs<"TrustCenterFilesCardFragment">;
|
||||
};
|
||||
|
||||
const node: ReaderFragment = {
|
||||
"argumentDefinitions": [],
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "TrustCenterFilesCardFragment",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "name",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "category",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "fileUrl",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "trustCenterVisibility",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "createdAt",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "updatedAt",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "TrustCenterFile",
|
||||
"abstractKey": null
|
||||
};
|
||||
|
||||
(node as any).hash = "33cb01782ca37fc776cd8e5dfde20f76";
|
||||
|
||||
export default node;
|
||||
Reference in New Issue
Block a user