@@ -1,389 +0,0 @@
|
|||||||
/**
|
|
||||||
* @generated SignedSource<<ca40d9ddba0f52570c2c9cece97e15dc>>
|
|
||||||
* @lightSyntaxTransform
|
|
||||||
* @nogrep
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* tslint:disable */
|
|
||||||
/* eslint-disable */
|
|
||||||
// @ts-nocheck
|
|
||||||
|
|
||||||
import { ConcreteRequest } from 'relay-runtime';
|
|
||||||
export type TrustCenterReferenceGraphQuery$variables = {
|
|
||||||
trustCenterId: string;
|
|
||||||
};
|
|
||||||
export type TrustCenterReferenceGraphQuery$data = {
|
|
||||||
readonly node: {
|
|
||||||
readonly __typename: "TrustCenter";
|
|
||||||
readonly id: string;
|
|
||||||
readonly references: {
|
|
||||||
readonly __id: string;
|
|
||||||
readonly edges: ReadonlyArray<{
|
|
||||||
readonly cursor: string;
|
|
||||||
readonly node: {
|
|
||||||
readonly canDelete: boolean;
|
|
||||||
readonly canUpdate: boolean;
|
|
||||||
readonly createdAt: string;
|
|
||||||
readonly description: string | null | undefined;
|
|
||||||
readonly id: string;
|
|
||||||
readonly logoUrl: string;
|
|
||||||
readonly name: string;
|
|
||||||
readonly rank: number;
|
|
||||||
readonly updatedAt: string;
|
|
||||||
readonly websiteUrl: string;
|
|
||||||
};
|
|
||||||
}>;
|
|
||||||
readonly pageInfo: {
|
|
||||||
readonly endCursor: string | null | undefined;
|
|
||||||
readonly hasNextPage: boolean;
|
|
||||||
readonly hasPreviousPage: boolean;
|
|
||||||
readonly startCursor: string | null | undefined;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
} | {
|
|
||||||
// This will never be '%other', but we need some
|
|
||||||
// value in case none of the concrete values match.
|
|
||||||
readonly __typename: "%other";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
export type TrustCenterReferenceGraphQuery = {
|
|
||||||
response: TrustCenterReferenceGraphQuery$data;
|
|
||||||
variables: TrustCenterReferenceGraphQuery$variables;
|
|
||||||
};
|
|
||||||
|
|
||||||
const node: ConcreteRequest = (function(){
|
|
||||||
var v0 = [
|
|
||||||
{
|
|
||||||
"defaultValue": null,
|
|
||||||
"kind": "LocalArgument",
|
|
||||||
"name": "trustCenterId"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
v1 = [
|
|
||||||
{
|
|
||||||
"kind": "Variable",
|
|
||||||
"name": "id",
|
|
||||||
"variableName": "trustCenterId"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
v2 = {
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "__typename",
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
v3 = {
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "id",
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
v4 = {
|
|
||||||
"kind": "Literal",
|
|
||||||
"name": "orderBy",
|
|
||||||
"value": {
|
|
||||||
"direction": "ASC",
|
|
||||||
"field": "RANK"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
v5 = {
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"concreteType": "PageInfo",
|
|
||||||
"kind": "LinkedField",
|
|
||||||
"name": "pageInfo",
|
|
||||||
"plural": false,
|
|
||||||
"selections": [
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "hasNextPage",
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "hasPreviousPage",
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "startCursor",
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "endCursor",
|
|
||||||
"storageKey": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
v6 = {
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"concreteType": "TrustCenterReferenceEdge",
|
|
||||||
"kind": "LinkedField",
|
|
||||||
"name": "edges",
|
|
||||||
"plural": true,
|
|
||||||
"selections": [
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "cursor",
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"concreteType": "TrustCenterReference",
|
|
||||||
"kind": "LinkedField",
|
|
||||||
"name": "node",
|
|
||||||
"plural": false,
|
|
||||||
"selections": [
|
|
||||||
(v3/*: any*/),
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "name",
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "description",
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "websiteUrl",
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "logoUrl",
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "rank",
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "createdAt",
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "updatedAt",
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": "canUpdate",
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"kind": "Literal",
|
|
||||||
"name": "action",
|
|
||||||
"value": "core:trust-center-reference:update"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "permission",
|
|
||||||
"storageKey": "permission(action:\"core:trust-center-reference:update\")"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": "canDelete",
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"kind": "Literal",
|
|
||||||
"name": "action",
|
|
||||||
"value": "core:trust-center-reference:delete"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "permission",
|
|
||||||
"storageKey": "permission(action:\"core:trust-center-reference:delete\")"
|
|
||||||
},
|
|
||||||
(v2/*: any*/)
|
|
||||||
],
|
|
||||||
"storageKey": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
v7 = {
|
|
||||||
"kind": "ClientExtension",
|
|
||||||
"selections": [
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "__id",
|
|
||||||
"storageKey": null
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
v8 = [
|
|
||||||
{
|
|
||||||
"kind": "Literal",
|
|
||||||
"name": "first",
|
|
||||||
"value": 100
|
|
||||||
},
|
|
||||||
(v4/*: any*/)
|
|
||||||
];
|
|
||||||
return {
|
|
||||||
"fragment": {
|
|
||||||
"argumentDefinitions": (v0/*: any*/),
|
|
||||||
"kind": "Fragment",
|
|
||||||
"metadata": null,
|
|
||||||
"name": "TrustCenterReferenceGraphQuery",
|
|
||||||
"selections": [
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": (v1/*: any*/),
|
|
||||||
"concreteType": null,
|
|
||||||
"kind": "LinkedField",
|
|
||||||
"name": "node",
|
|
||||||
"plural": false,
|
|
||||||
"selections": [
|
|
||||||
(v2/*: any*/),
|
|
||||||
{
|
|
||||||
"kind": "InlineFragment",
|
|
||||||
"selections": [
|
|
||||||
(v3/*: any*/),
|
|
||||||
{
|
|
||||||
"kind": "RequiredField",
|
|
||||||
"field": {
|
|
||||||
"alias": "references",
|
|
||||||
"args": [
|
|
||||||
(v4/*: any*/)
|
|
||||||
],
|
|
||||||
"concreteType": "TrustCenterReferenceConnection",
|
|
||||||
"kind": "LinkedField",
|
|
||||||
"name": "__TrustCenterReferencesSection_references_connection",
|
|
||||||
"plural": false,
|
|
||||||
"selections": [
|
|
||||||
(v5/*: any*/),
|
|
||||||
{
|
|
||||||
"kind": "RequiredField",
|
|
||||||
"field": (v6/*: any*/),
|
|
||||||
"action": "THROW"
|
|
||||||
},
|
|
||||||
(v7/*: any*/)
|
|
||||||
],
|
|
||||||
"storageKey": "__TrustCenterReferencesSection_references_connection(orderBy:{\"direction\":\"ASC\",\"field\":\"RANK\"})"
|
|
||||||
},
|
|
||||||
"action": "THROW"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "TrustCenter",
|
|
||||||
"abstractKey": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"storageKey": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "Query",
|
|
||||||
"abstractKey": null
|
|
||||||
},
|
|
||||||
"kind": "Request",
|
|
||||||
"operation": {
|
|
||||||
"argumentDefinitions": (v0/*: any*/),
|
|
||||||
"kind": "Operation",
|
|
||||||
"name": "TrustCenterReferenceGraphQuery",
|
|
||||||
"selections": [
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": (v1/*: any*/),
|
|
||||||
"concreteType": null,
|
|
||||||
"kind": "LinkedField",
|
|
||||||
"name": "node",
|
|
||||||
"plural": false,
|
|
||||||
"selections": [
|
|
||||||
(v2/*: any*/),
|
|
||||||
(v3/*: any*/),
|
|
||||||
{
|
|
||||||
"kind": "InlineFragment",
|
|
||||||
"selections": [
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": (v8/*: any*/),
|
|
||||||
"concreteType": "TrustCenterReferenceConnection",
|
|
||||||
"kind": "LinkedField",
|
|
||||||
"name": "references",
|
|
||||||
"plural": false,
|
|
||||||
"selections": [
|
|
||||||
(v5/*: any*/),
|
|
||||||
(v6/*: any*/),
|
|
||||||
(v7/*: any*/)
|
|
||||||
],
|
|
||||||
"storageKey": "references(first:100,orderBy:{\"direction\":\"ASC\",\"field\":\"RANK\"})"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": (v8/*: any*/),
|
|
||||||
"filters": [
|
|
||||||
"orderBy"
|
|
||||||
],
|
|
||||||
"handle": "connection",
|
|
||||||
"key": "TrustCenterReferencesSection_references",
|
|
||||||
"kind": "LinkedHandle",
|
|
||||||
"name": "references"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "TrustCenter",
|
|
||||||
"abstractKey": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"storageKey": null
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"params": {
|
|
||||||
"cacheID": "3eaf772859927eca50f824a7298fd2d5",
|
|
||||||
"id": null,
|
|
||||||
"metadata": {
|
|
||||||
"connection": [
|
|
||||||
{
|
|
||||||
"count": null,
|
|
||||||
"cursor": null,
|
|
||||||
"direction": "forward",
|
|
||||||
"path": [
|
|
||||||
"node",
|
|
||||||
"references"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"name": "TrustCenterReferenceGraphQuery",
|
|
||||||
"operationKind": "query",
|
|
||||||
"text": "query TrustCenterReferenceGraphQuery(\n $trustCenterId: ID!\n) {\n node(id: $trustCenterId) {\n __typename\n ... on TrustCenter {\n id\n references(first: 100, orderBy: {field: RANK, direction: ASC}) {\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n edges {\n cursor\n node {\n id\n name\n description\n websiteUrl\n logoUrl\n rank\n createdAt\n updatedAt\n canUpdate: permission(action: \"core:trust-center-reference:update\")\n canDelete: permission(action: \"core:trust-center-reference:delete\")\n __typename\n }\n }\n }\n }\n id\n }\n}\n"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
|
|
||||||
(node as any).hash = "5c1e65a30423ec4357ef2cb546bca387";
|
|
||||||
|
|
||||||
export default node;
|
|
||||||
@@ -1,259 +0,0 @@
|
|||||||
import { safeOpenUrl } from "@probo/helpers";
|
|
||||||
import { useTranslate } from "@probo/i18n";
|
|
||||||
import {
|
|
||||||
Avatar,
|
|
||||||
Button,
|
|
||||||
IconArrowLink,
|
|
||||||
IconPencil,
|
|
||||||
IconPlusLarge,
|
|
||||||
IconTrashCan,
|
|
||||||
Table,
|
|
||||||
Tbody,
|
|
||||||
Td,
|
|
||||||
Th,
|
|
||||||
Thead,
|
|
||||||
Tr,
|
|
||||||
} from "@probo/ui";
|
|
||||||
import { useRef, useState } from "react";
|
|
||||||
import { useLazyLoadQuery } from "react-relay";
|
|
||||||
|
|
||||||
import type {
|
|
||||||
TrustCenterReferenceGraphQuery$data,
|
|
||||||
TrustCenterReferenceGraphQuery,
|
|
||||||
} from "#/__generated__/core/TrustCenterReferenceGraphQuery.graphql";
|
|
||||||
import {
|
|
||||||
trustCenterReferencesQuery,
|
|
||||||
useUpdateTrustCenterReferenceRankMutation,
|
|
||||||
} from "#/hooks/graph/TrustCenterReferenceGraph";
|
|
||||||
|
|
||||||
import { DeleteTrustCenterReferenceDialog } from "./DeleteTrustCenterReferenceDialog";
|
|
||||||
import {
|
|
||||||
TrustCenterReferenceDialog,
|
|
||||||
type TrustCenterReferenceDialogRef,
|
|
||||||
} from "./TrustCenterReferenceDialog";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
trustCenterId: string;
|
|
||||||
canCreateReference: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Reference = Extract<
|
|
||||||
TrustCenterReferenceGraphQuery$data["node"],
|
|
||||||
{ __typename: "TrustCenter" }
|
|
||||||
>["references"]["edges"][number]["node"];
|
|
||||||
|
|
||||||
export function TrustCenterReferencesSection({
|
|
||||||
canCreateReference,
|
|
||||||
trustCenterId,
|
|
||||||
}: Props) {
|
|
||||||
const { __ } = useTranslate();
|
|
||||||
const dialogRef = useRef<TrustCenterReferenceDialogRef>(null);
|
|
||||||
const [draggedIndex, setDraggedIndex] = useState<number | null>(null);
|
|
||||||
const [dragOverIndex, setDragOverIndex] = useState<number | null>(null);
|
|
||||||
const [refetchKey, setRefetchKey] = useState(0);
|
|
||||||
const { node: trustCenterNode }
|
|
||||||
= useLazyLoadQuery<TrustCenterReferenceGraphQuery>(
|
|
||||||
trustCenterReferencesQuery,
|
|
||||||
{ trustCenterId: trustCenterId || "" },
|
|
||||||
{ fetchPolicy: "network-only", fetchKey: refetchKey },
|
|
||||||
);
|
|
||||||
if (trustCenterNode.__typename !== "TrustCenter") {
|
|
||||||
throw new Error("invalid node type");
|
|
||||||
}
|
|
||||||
const [updateRank] = useUpdateTrustCenterReferenceRankMutation();
|
|
||||||
|
|
||||||
const references
|
|
||||||
= trustCenterNode?.references?.edges?.map(edge => edge.node) || [];
|
|
||||||
const referencesConnectionId = trustCenterNode?.references?.__id || "";
|
|
||||||
|
|
||||||
const handleCreate = () => {
|
|
||||||
if (referencesConnectionId) {
|
|
||||||
dialogRef.current?.openCreate(trustCenterId, referencesConnectionId);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEdit = (reference: Reference) => {
|
|
||||||
dialogRef.current?.openEdit(reference);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleVisitWebsite = (websiteUrl: string) => {
|
|
||||||
safeOpenUrl(websiteUrl);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDragStart = (index: number) => {
|
|
||||||
setDraggedIndex(index);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDragOver = (e: React.DragEvent, index: number) => {
|
|
||||||
e.preventDefault();
|
|
||||||
if (draggedIndex !== index) {
|
|
||||||
setDragOverIndex(index);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDrop = async (targetIndex: number) => {
|
|
||||||
if (draggedIndex === null || draggedIndex === targetIndex) {
|
|
||||||
setDraggedIndex(null);
|
|
||||||
setDragOverIndex(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const draggedRef = references[draggedIndex];
|
|
||||||
const targetRank = references[targetIndex].rank;
|
|
||||||
|
|
||||||
await updateRank({
|
|
||||||
variables: {
|
|
||||||
input: {
|
|
||||||
id: draggedRef.id,
|
|
||||||
rank: targetRank,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
onCompleted: () => {
|
|
||||||
setRefetchKey(prev => prev + 1);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
setDraggedIndex(null);
|
|
||||||
setDragOverIndex(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<div>
|
|
||||||
<h2 className="text-base font-medium">{__("Trusted by")}</h2>
|
|
||||||
<p className="text-sm text-txt-tertiary">
|
|
||||||
{__("Showcase your customers and partners on your trust center")}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
{canCreateReference && (
|
|
||||||
<Button icon={IconPlusLarge} onClick={handleCreate}>
|
|
||||||
{__("Add Reference")}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Table>
|
|
||||||
<Thead>
|
|
||||||
<Tr>
|
|
||||||
<Th>{__("Name")}</Th>
|
|
||||||
<Th>{__("Description")}</Th>
|
|
||||||
<Th></Th>
|
|
||||||
</Tr>
|
|
||||||
</Thead>
|
|
||||||
<Tbody>
|
|
||||||
{references.length === 0 && (
|
|
||||||
<Tr>
|
|
||||||
<Td colSpan={3} className="text-center text-txt-secondary">
|
|
||||||
{__("No references available")}
|
|
||||||
</Td>
|
|
||||||
</Tr>
|
|
||||||
)}
|
|
||||||
{references.map((reference: Reference, index: number) => (
|
|
||||||
<ReferenceRow
|
|
||||||
key={reference.id}
|
|
||||||
reference={reference}
|
|
||||||
index={index}
|
|
||||||
isDragging={draggedIndex === index}
|
|
||||||
isDropTarget={dragOverIndex === index && draggedIndex !== index}
|
|
||||||
onEdit={() => handleEdit(reference)}
|
|
||||||
connectionId={referencesConnectionId}
|
|
||||||
onVisitWebsite={() => handleVisitWebsite(reference.websiteUrl)}
|
|
||||||
onDragStart={() => handleDragStart(index)}
|
|
||||||
onDragOver={e => handleDragOver(e, index)}
|
|
||||||
onDrop={() => void handleDrop(index)}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Tbody>
|
|
||||||
</Table>
|
|
||||||
|
|
||||||
<p className="text-xs text-txt-tertiary">
|
|
||||||
{__("Drag and drop references to change their displayed order")}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<TrustCenterReferenceDialog ref={dialogRef} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReferenceRowProps = {
|
|
||||||
reference: Reference;
|
|
||||||
index: number;
|
|
||||||
isDragging: boolean;
|
|
||||||
isDropTarget: boolean;
|
|
||||||
onEdit: () => void;
|
|
||||||
connectionId: string;
|
|
||||||
onVisitWebsite: () => void;
|
|
||||||
onDragStart: () => void;
|
|
||||||
onDragOver: (e: React.DragEvent) => void;
|
|
||||||
onDrop: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
function ReferenceRow({
|
|
||||||
reference,
|
|
||||||
isDragging,
|
|
||||||
isDropTarget,
|
|
||||||
onEdit,
|
|
||||||
connectionId,
|
|
||||||
onVisitWebsite,
|
|
||||||
onDragStart,
|
|
||||||
onDragOver,
|
|
||||||
onDrop,
|
|
||||||
}: ReferenceRowProps) {
|
|
||||||
const [isMouseDown, setIsMouseDown] = useState(false);
|
|
||||||
|
|
||||||
const className = [
|
|
||||||
isDragging && "opacity-50 cursor-grabbing",
|
|
||||||
!isDragging && !isMouseDown && "cursor-grab",
|
|
||||||
!isDragging && isMouseDown && "cursor-grabbing",
|
|
||||||
isDropTarget && "!bg-primary-50 border-y-2 border-primary-500",
|
|
||||||
]
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(" ");
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tr
|
|
||||||
draggable
|
|
||||||
onDragStart={onDragStart}
|
|
||||||
onDragOver={onDragOver}
|
|
||||||
onDrop={onDrop}
|
|
||||||
onMouseDown={() => setIsMouseDown(true)}
|
|
||||||
onMouseUp={() => setIsMouseDown(false)}
|
|
||||||
onMouseLeave={() => setIsMouseDown(false)}
|
|
||||||
className={className}
|
|
||||||
>
|
|
||||||
<Td>
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<Avatar src={reference.logoUrl} name={reference.name} size="m" />
|
|
||||||
<span className="font-medium">{reference.name}</span>
|
|
||||||
</div>
|
|
||||||
</Td>
|
|
||||||
<Td>
|
|
||||||
<span className="text-txt-secondary line-clamp-2">
|
|
||||||
{reference.description}
|
|
||||||
</span>
|
|
||||||
</Td>
|
|
||||||
<Td noLink width={200} className="text-end">
|
|
||||||
<div className="flex gap-2 justify-end">
|
|
||||||
<Button
|
|
||||||
variant="secondary"
|
|
||||||
icon={IconArrowLink}
|
|
||||||
onClick={onVisitWebsite}
|
|
||||||
/>
|
|
||||||
{reference.canUpdate && (
|
|
||||||
<Button variant="secondary" icon={IconPencil} onClick={onEdit} />
|
|
||||||
)}
|
|
||||||
{reference.canDelete && (
|
|
||||||
<DeleteTrustCenterReferenceDialog
|
|
||||||
referenceId={reference.id}
|
|
||||||
referenceName={reference.name}
|
|
||||||
connectionId={connectionId}
|
|
||||||
>
|
|
||||||
<Button variant="danger" icon={IconTrashCan} />
|
|
||||||
</DeleteTrustCenterReferenceDialog>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Td>
|
|
||||||
</Tr>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -6,47 +6,6 @@ import type { TrustCenterReferenceGraphUpdateMutation } from "#/__generated__/co
|
|||||||
import type { TrustCenterReferenceGraphUpdateRankMutation } from "#/__generated__/core/TrustCenterReferenceGraphUpdateRankMutation.graphql";
|
import type { TrustCenterReferenceGraphUpdateRankMutation } from "#/__generated__/core/TrustCenterReferenceGraphUpdateRankMutation.graphql";
|
||||||
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
|
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
|
||||||
|
|
||||||
export const trustCenterReferencesQuery = graphql`
|
|
||||||
query TrustCenterReferenceGraphQuery($trustCenterId: ID!) {
|
|
||||||
node(id: $trustCenterId) {
|
|
||||||
__typename
|
|
||||||
... on TrustCenter {
|
|
||||||
id
|
|
||||||
references(first: 100, orderBy: { field: RANK, direction: ASC })
|
|
||||||
@connection(key: "TrustCenterReferencesSection_references")
|
|
||||||
@required(action: THROW) {
|
|
||||||
__id
|
|
||||||
pageInfo {
|
|
||||||
hasNextPage
|
|
||||||
hasPreviousPage
|
|
||||||
startCursor
|
|
||||||
endCursor
|
|
||||||
}
|
|
||||||
edges @required(action: THROW) {
|
|
||||||
cursor
|
|
||||||
node {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
description
|
|
||||||
websiteUrl
|
|
||||||
logoUrl
|
|
||||||
rank
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
canUpdate: permission(
|
|
||||||
action: "core:trust-center-reference:update"
|
|
||||||
)
|
|
||||||
canDelete: permission(
|
|
||||||
action: "core:trust-center-reference:delete"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const createTrustCenterReferenceMutation = graphql`
|
export const createTrustCenterReferenceMutation = graphql`
|
||||||
mutation TrustCenterReferenceGraphCreateMutation(
|
mutation TrustCenterReferenceGraphCreateMutation(
|
||||||
$input: CreateTrustCenterReferenceInput!
|
$input: CreateTrustCenterReferenceInput!
|
||||||
|
|||||||
@@ -1,294 +0,0 @@
|
|||||||
import { useTranslate } from "@probo/i18n";
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Card,
|
|
||||||
Checkbox,
|
|
||||||
Dropzone,
|
|
||||||
IconTrashCan,
|
|
||||||
Spinner,
|
|
||||||
useToast,
|
|
||||||
} from "@probo/ui";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { useOutletContext } from "react-router";
|
|
||||||
|
|
||||||
import type { TrustCenterGraphQuery$data } from "#/__generated__/core/TrustCenterGraphQuery.graphql";
|
|
||||||
import {
|
|
||||||
useDeleteTrustCenterNDAMutation,
|
|
||||||
useUpdateTrustCenterMutation,
|
|
||||||
useUploadTrustCenterNDAMutation,
|
|
||||||
} from "#/hooks/graph/TrustCenterGraph";
|
|
||||||
|
|
||||||
import { SlackConnections } from "../../../components/organizations/SlackConnection";
|
|
||||||
|
|
||||||
export default function TrustCenterOverviewTab() {
|
|
||||||
const { __ } = useTranslate();
|
|
||||||
const { toast } = useToast();
|
|
||||||
const { organization } = useOutletContext<TrustCenterGraphQuery$data>();
|
|
||||||
|
|
||||||
const [updateTrustCenter, isUpdating] = useUpdateTrustCenterMutation();
|
|
||||||
const [uploadNDA, isUploadingNDA] = useUploadTrustCenterNDAMutation();
|
|
||||||
const [deleteNDA, isDeletingNDA] = useDeleteTrustCenterNDAMutation();
|
|
||||||
const [isActive, setIsActive] = useState(
|
|
||||||
organization.trustCenter?.active || false,
|
|
||||||
);
|
|
||||||
|
|
||||||
const canUpdateTrustCenter = organization.trustCenter?.canUpdate;
|
|
||||||
|
|
||||||
const handleToggleActive = async (active: boolean) => {
|
|
||||||
if (!organization.trustCenter?.id) {
|
|
||||||
toast({
|
|
||||||
title: __("Error"),
|
|
||||||
description: __("Trust center not found"),
|
|
||||||
variant: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsActive(active);
|
|
||||||
|
|
||||||
await updateTrustCenter({
|
|
||||||
variables: {
|
|
||||||
input: {
|
|
||||||
trustCenterId: organization.trustCenter.id,
|
|
||||||
active,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
onError: () => {
|
|
||||||
setIsActive(!active);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleNDAUpload = async (files: File[]) => {
|
|
||||||
if (!organization.trustCenter?.id) {
|
|
||||||
toast({
|
|
||||||
title: __("Error"),
|
|
||||||
description: __("Trust center not found"),
|
|
||||||
variant: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (files.length === 0) return;
|
|
||||||
|
|
||||||
const file = files[0];
|
|
||||||
|
|
||||||
await uploadNDA({
|
|
||||||
variables: {
|
|
||||||
input: {
|
|
||||||
trustCenterId: organization.trustCenter.id,
|
|
||||||
fileName: file.name,
|
|
||||||
file: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
uploadables: {
|
|
||||||
"input.file": file,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleNDADelete = async () => {
|
|
||||||
if (!organization.trustCenter?.id) {
|
|
||||||
toast({
|
|
||||||
title: __("Error"),
|
|
||||||
description: __("Trust center not found"),
|
|
||||||
variant: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!confirm(__("Are you sure you want to delete the NDA file?"))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await deleteNDA({
|
|
||||||
variables: {
|
|
||||||
input: {
|
|
||||||
trustCenterId: organization.trustCenter.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const trustCenterUrl = organization.trustCenter?.id
|
|
||||||
? organization.customDomain?.domain
|
|
||||||
? `https://${organization.customDomain.domain}`
|
|
||||||
: `${window.location.origin}/trust/${organization.trustCenter.id}`
|
|
||||||
: null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="space-y-6">
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<h2 className="text-base font-medium">{__("Trust Center Status")}</h2>
|
|
||||||
{isUpdating && <Spinner />}
|
|
||||||
</div>
|
|
||||||
<Card padded className="space-y-4">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<div className="space-y-1">
|
|
||||||
<h3 className="font-medium">{__("Activate Trust Center")}</h3>
|
|
||||||
<p className="text-sm text-txt-tertiary">
|
|
||||||
{__(
|
|
||||||
"Make your trust center publicly accessible to build customer confidence",
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<Checkbox
|
|
||||||
checked={isActive}
|
|
||||||
onChange={checked => void handleToggleActive(checked)}
|
|
||||||
disabled={!canUpdateTrustCenter}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{isActive && trustCenterUrl && (
|
|
||||||
<div className="mt-4 p-4 bg-accent-light rounded-lg border border-accent">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<div>
|
|
||||||
<h4 className="font-medium text-accent-dark">
|
|
||||||
{__("Your Trust Center is Live!")}
|
|
||||||
</h4>
|
|
||||||
<p className="text-sm text-accent-dark mt-1">
|
|
||||||
{__("Your customers can now access your trust center at:")}
|
|
||||||
</p>
|
|
||||||
<a
|
|
||||||
href={trustCenterUrl}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-sm font-mono text-accent underline hover:no-underline"
|
|
||||||
>
|
|
||||||
{trustCenterUrl}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
variant="secondary"
|
|
||||||
onClick={() =>
|
|
||||||
window.open(trustCenterUrl, "_blank", "noopener,noreferrer")}
|
|
||||||
>
|
|
||||||
{__("View")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!isActive && (
|
|
||||||
<div className="mt-4 p-4 bg-tertiary rounded-lg border border-border-solid">
|
|
||||||
<h4 className="font-medium text-txt-secondary">
|
|
||||||
{__("Trust Center is Inactive")}
|
|
||||||
</h4>
|
|
||||||
<p className="text-sm text-txt-tertiary mt-1">
|
|
||||||
{__(
|
|
||||||
"Your trust center is currently not accessible to the public. Enable it to start sharing your compliance status.",
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
{organization.trustCenter?.canGetNDA && (
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<h2 className="text-base font-medium">
|
|
||||||
{__("Non-Disclosure Agreement")}
|
|
||||||
</h2>
|
|
||||||
{(isUploadingNDA || isDeletingNDA) && <Spinner />}
|
|
||||||
</div>
|
|
||||||
<Card padded className="space-y-4">
|
|
||||||
<div className="space-y-2">
|
|
||||||
{!organization.trustCenter?.ndaFileName
|
|
||||||
&& organization.trustCenter.canUploadNDA
|
|
||||||
? (
|
|
||||||
<p className="text-sm text-txt-tertiary">
|
|
||||||
{__(
|
|
||||||
"Upload a Non-Disclosure Agreement that visitors must accept before accessing your trust center",
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
)
|
|
||||||
: (
|
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
{organization.trustCenter?.ndaFileName
|
|
||||||
? (
|
|
||||||
<div className="space-y-3">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<div className="space-y-1">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<p className="text-sm font-medium">
|
|
||||||
{organization.trustCenter.ndaFileName
|
|
||||||
|| __("Non-Disclosure Agreement")}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-txt-tertiary">
|
|
||||||
{__(
|
|
||||||
"Visitors will need to accept this NDA before accessing your trust center",
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
variant="secondary"
|
|
||||||
onClick={() => {
|
|
||||||
if (organization.trustCenter?.ndaFileUrl) {
|
|
||||||
window.open(
|
|
||||||
organization.trustCenter.ndaFileUrl,
|
|
||||||
"_blank",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{__("Download PDF")}
|
|
||||||
</Button>
|
|
||||||
{organization.trustCenter?.canDeleteNDA && (
|
|
||||||
<Button
|
|
||||||
variant="quaternary"
|
|
||||||
icon={IconTrashCan}
|
|
||||||
onClick={() => void handleNDADelete()}
|
|
||||||
disabled={isDeletingNDA}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
: (
|
|
||||||
<>
|
|
||||||
{canUpdateTrustCenter
|
|
||||||
? (
|
|
||||||
<Dropzone
|
|
||||||
description={__("Upload PDF files up to 10MB")}
|
|
||||||
isUploading={isUploadingNDA}
|
|
||||||
onDrop={files => void handleNDAUpload(files)}
|
|
||||||
accept={{
|
|
||||||
"application/pdf": [".pdf"],
|
|
||||||
}}
|
|
||||||
maxSize={10}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
: (
|
|
||||||
<p className="text-sm text-txt-tertiary">
|
|
||||||
{__("No NDA file uploaded")}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="space-y-4">
|
|
||||||
<h2 className="text-base font-medium">{__("Integrations")}</h2>
|
|
||||||
<Card padded>
|
|
||||||
<SlackConnections
|
|
||||||
canUpdate={!!organization.trustCenter?.canUpdate}
|
|
||||||
organizationId={organization.id!}
|
|
||||||
slackConnections={
|
|
||||||
organization.slackConnections?.edges?.map(edge => edge.node)
|
|
||||||
?? []
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import { useOutletContext } from "react-router";
|
|
||||||
|
|
||||||
import type { TrustCenterGraphQuery$data } from "#/__generated__/core/TrustCenterGraphQuery.graphql";
|
|
||||||
import { TrustCenterReferencesSection } from "#/components/trustCenter/TrustCenterReferencesSection";
|
|
||||||
|
|
||||||
export default function TrustCenterReferencesTab() {
|
|
||||||
const { organization } = useOutletContext<TrustCenterGraphQuery$data>();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="space-y-4">
|
|
||||||
{organization.trustCenter?.id && (
|
|
||||||
<TrustCenterReferencesSection
|
|
||||||
trustCenterId={organization.trustCenter.id}
|
|
||||||
canCreateReference={!!organization.trustCenter.canCreateReference}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -29,22 +29,6 @@ export const trustCenterRoutes = [
|
|||||||
lazy(() => import("#/pages/organizations/trustCenter/TrustCenterPage")),
|
lazy(() => import("#/pages/organizations/trustCenter/TrustCenterPage")),
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
{
|
|
||||||
index: true,
|
|
||||||
Fallback: LinkCardSkeleton,
|
|
||||||
Component: lazy(
|
|
||||||
() =>
|
|
||||||
import("#/pages/organizations/trustCenter/TrustCenterOverviewTab"),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "trust-by",
|
|
||||||
Fallback: LinkCardSkeleton,
|
|
||||||
Component: lazy(
|
|
||||||
() =>
|
|
||||||
import("#/pages/organizations/trustCenter/TrustCenterReferencesTab"),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: "audits",
|
path: "audits",
|
||||||
Fallback: LinkCardSkeleton,
|
Fallback: LinkCardSkeleton,
|
||||||
|
|||||||
Reference in New Issue
Block a user