diff --git a/packages/web/lib/networking/mutations/createLabelMutation.ts b/packages/web/lib/networking/mutations/createLabelMutation.ts new file mode 100644 index 000000000..2da414b22 --- /dev/null +++ b/packages/web/lib/networking/mutations/createLabelMutation.ts @@ -0,0 +1,42 @@ +import { gql } from 'graphql-request' +import { gqlFetcher } from '../networkHelpers' + +export async function createLabelMutation( + name: string, + color: string, + description?: string +): Promise { + const mutation = gql` + mutation { + createLabel( + input: { + color: "${color}" + name: "${name}" + description: "${description}" + } + ) { + ... on CreateLabelSuccess { + label { + id + name + color + description + createdAt + } + } + ... on CreateLabelError { + errorCodes + } + } + } + ` + + try { + const data = await gqlFetcher(mutation) + console.log('created label', data) + return data + } catch (error) { + console.log('createLabelMutation error', error) + return undefined + } +} diff --git a/packages/web/lib/networking/mutations/deleteLabelMutation.ts b/packages/web/lib/networking/mutations/deleteLabelMutation.ts new file mode 100644 index 000000000..cef0b4d53 --- /dev/null +++ b/packages/web/lib/networking/mutations/deleteLabelMutation.ts @@ -0,0 +1,34 @@ +import { gql } from 'graphql-request' +import { gqlFetcher } from '../networkHelpers' + +export async function deleteLabelMutation( + labelId: string +): Promise { + const mutation = gql` + mutation { + deleteLabel(id: "${labelId}") { + ... on DeleteLabelSuccess { + label { + id + name + color + description + createdAt + } + } + ... on DeleteLabelError { + errorCodes + } + } + } + ` + + try { + const data = await gqlFetcher(mutation) + console.log('deleted label', data) + return data + } catch (error) { + console.log('deleteLabelMutation error', error) + return undefined + } +} diff --git a/packages/web/lib/networking/queries/useGetLabelsQuery.tsx b/packages/web/lib/networking/queries/useGetLabelsQuery.tsx new file mode 100644 index 000000000..d132d3042 --- /dev/null +++ b/packages/web/lib/networking/queries/useGetLabelsQuery.tsx @@ -0,0 +1,70 @@ +import { gql } from 'graphql-request' +import useSWR from 'swr' +import { publicGqlFetcher } from '../networkHelpers' + +type LabelsQueryResponse = { + isValidating: boolean + labels: Label[] + revalidate: () => void +} + +type LabelsResponseData = { + labels?: LabelsData +} + +type LabelsData = { + labels?: unknown +} + +export type Label = { + id: string + name: string + color: string + description?: string + createdAt: Date +} + +export function useGetLabelsQuery(): LabelsQueryResponse { + const query = gql` + query GetLabels { + labels { + ... on LabelsSuccess { + labels { + id + name + color + description + createdAt + } + } + ... on LabelsError { + errorCodes + } + } + } + ` + + const { data, mutate, error, isValidating } = useSWR(query, publicGqlFetcher) + + try { + if (data) { + const result = data as LabelsResponseData + const labels = result.labels?.labels as Label[] + return { + isValidating, + labels, + revalidate: () => { + mutate() + }, + } + } + } catch (error) { + console.log('error', error) + } + return { + isValidating: false, + labels: [], + // eslint-disable-next-line @typescript-eslint/no-empty-function + revalidate: () => {}, + } +} diff --git a/packages/web/pages/settings/labels.tsx b/packages/web/pages/settings/labels.tsx new file mode 100644 index 000000000..971890030 --- /dev/null +++ b/packages/web/pages/settings/labels.tsx @@ -0,0 +1,107 @@ +import { PrimaryLayout } from '../../components/templates/PrimaryLayout' +import { Button } from '../../components/elements/Button' +import { Box, VStack } from '../../components/elements/LayoutPrimitives' +import { toast, Toaster } from 'react-hot-toast' +import { useGetLabelsQuery } from '../../lib/networking/queries/useGetLabelsQuery' +import { createLabelMutation } from '../../lib/networking/mutations/createLabelMutation' +import { deleteLabelMutation } from '../../lib/networking/mutations/deleteLabelMutation' +import { useState } from 'react' + +export default function LabelsPage(): JSX.Element { + const { labels, revalidate, isValidating } = useGetLabelsQuery() + const [name, setName] = useState('') + const [color, setColor] = useState('') + const [description, setDescription] = useState('') + + async function createLabel(): Promise { + const res = await createLabelMutation(name, color, description) + if (res) { + if (res.createLabel.errorCodes && res.createLabel.errorCodes.length > 0) { + toast.error(res.createLabel.errorCodes[0]) + } else { + toast.success('Label created') + setName('') + setColor('') + setDescription('') + revalidate() + } + } else { + toast.error('Failed to create label') + } + } + + async function deleteLabel(id: string): Promise { + await deleteLabelMutation(id) + revalidate() + } + + return ( + + + +

Create a new label

+
=> { + e.preventDefault() + await createLabel() + }} + > + { + setName(event.target.value) + }} + /> + { + setColor(event.target.value) + }} + /> + { + setDescription(event.target.value) + }} + /> + +
+ +

Labels

+ {labels && + labels.map((label) => { + return ( + +
=> { + e.preventDefault() + await deleteLabel(label.id) + }} + > + + + + +
+
+ ) + })} +
+
+ ) +}