From 76a07b924ff9f55622866a76ea0673bf5c2a0a80 Mon Sep 17 00:00:00 2001 From: Oksamies Date: Tue, 28 Nov 2023 02:05:39 +0200 Subject: [PATCH] WIP: Add TeamDetails edit form --- .../src/components/FormTextInput.tsx | 10 ++- .../src/forms/TeamDetailsEdit.module.css | 65 ++++++++++++++++++ .../src/forms/TeamDetailsEdit.tsx | 67 +++++++++++++++++++ packages/cyberstorm-forms/src/index.ts | 1 + .../TeamSettings/TeamDetails/TeamDetails.tsx | 47 +------------ .../src/fetch/teamDetailsEdit.ts | 27 ++++++++ packages/thunderstore-api/src/index.ts | 1 + packages/ts-api-react-forms/src/ApiForm.tsx | 4 +- packages/ts-api-react-forms/src/index.ts | 1 + packages/ts-api-react-forms/src/schema.ts | 6 ++ packages/ts-api-react-forms/src/useApiForm.ts | 5 +- packages/ts-api-react/src/useApiCall.ts | 7 +- 12 files changed, 189 insertions(+), 52 deletions(-) create mode 100644 packages/cyberstorm-forms/src/forms/TeamDetailsEdit.module.css create mode 100644 packages/cyberstorm-forms/src/forms/TeamDetailsEdit.tsx create mode 100644 packages/thunderstore-api/src/fetch/teamDetailsEdit.ts diff --git a/packages/cyberstorm-forms/src/components/FormTextInput.tsx b/packages/cyberstorm-forms/src/components/FormTextInput.tsx index 120f0d948..bf9513957 100644 --- a/packages/cyberstorm-forms/src/components/FormTextInput.tsx +++ b/packages/cyberstorm-forms/src/components/FormTextInput.tsx @@ -4,6 +4,7 @@ import { z, ZodObject, ZodRawShape } from "zod"; import { Path, useController } from "react-hook-form"; import { TextInput } from "@thunderstore/cyberstorm"; import styles from "./FormTextInput.module.css"; +import React from "react"; export type FormTextInputProps< Schema extends ZodObject, @@ -13,17 +14,24 @@ export type FormTextInputProps< schema: Schema; name: Path>; placeholder?: string; + existingValue?: string; }; export function FormTextInput< Schema extends ZodObject, Z extends ZodRawShape ->({ name, placeholder }: FormTextInputProps) { +>({ name, placeholder, existingValue }: FormTextInputProps) { const { field, fieldState: { isDirty, invalid, error }, formState: { isSubmitting, disabled }, } = useController({ name }); + if (existingValue) { + React.useEffect(() => { + field.onChange(existingValue); + }, [existingValue]); + } + return ( <> div { + width: 100%; +} + +.line { + margin: var(--space--24) 0; + border-bottom: var(--border-width--px) solid var(--color-surface--4); +} + +.avatarContent { + display: flex; + flex-direction: row; + gap: var(--gap--32); + align-items: center; +} + +.saveChangesWrapper { + display: flex; + flex-direction: row-reverse; +} + +@media (max-width: 30rem) { + .donationLink { + flex-direction: column; + gap: var(--gap--16); + align-items: flex-start; + } +} diff --git a/packages/cyberstorm-forms/src/forms/TeamDetailsEdit.tsx b/packages/cyberstorm-forms/src/forms/TeamDetailsEdit.tsx new file mode 100644 index 000000000..d22dafcdf --- /dev/null +++ b/packages/cyberstorm-forms/src/forms/TeamDetailsEdit.tsx @@ -0,0 +1,67 @@ +"use client"; + +import styles from "./TeamDetailsEdit.module.css"; +import { teamDetailsEdit } from "@thunderstore/thunderstore-api"; +import { + ApiForm, + teamDetailsEditFormSchema, +} from "@thunderstore/ts-api-react-forms"; +import { + FormSubmitButton, + FormTextInput, + useFormToaster, +} from "@thunderstore/cyberstorm-forms"; +import { useDapper } from "@thunderstore/dapper"; +import { usePromise } from "@thunderstore/use-promise"; +import { SettingItem } from "@thunderstore/cyberstorm/src/components/SettingItem/SettingItem"; + +export function TeamDetailsEdit({ teamName }: { teamName: string }) { + const toaster = useFormToaster({ + successMessage: "Changes saved", + }); + + const dapper = useDapper(); + const team = usePromise(dapper.getTeamDetails, [teamName]); + + return ( + +
+
+ +
URL
+
+
+ +
+
+
+ } + /> +
+
+ +
+ +
+ ); +} + +TeamDetailsEdit.displayName = "TeamDetailsEdit"; diff --git a/packages/cyberstorm-forms/src/index.ts b/packages/cyberstorm-forms/src/index.ts index a3a9912fb..5bda695a7 100644 --- a/packages/cyberstorm-forms/src/index.ts +++ b/packages/cyberstorm-forms/src/index.ts @@ -5,3 +5,4 @@ export { FormMultiSelectSearch } from "./components/FormMultiSelectSearch"; export { FormSwitch } from "./components/FormSwitch"; export { FormTextInput } from "./components/FormTextInput"; export { CreateTeamForm } from "./forms/CreateTeamForm"; +export { TeamDetailsEdit } from "./forms/TeamDetailsEdit"; diff --git a/packages/cyberstorm/src/components/Layout/Teams/TeamSettings/TeamDetails/TeamDetails.tsx b/packages/cyberstorm/src/components/Layout/Teams/TeamSettings/TeamDetails/TeamDetails.tsx index 414084f0b..77d843e08 100644 --- a/packages/cyberstorm/src/components/Layout/Teams/TeamSettings/TeamDetails/TeamDetails.tsx +++ b/packages/cyberstorm/src/components/Layout/Teams/TeamSettings/TeamDetails/TeamDetails.tsx @@ -1,12 +1,4 @@ -import { useDapper } from "@thunderstore/dapper"; -import { usePromise } from "@thunderstore/use-promise"; -import styles from "./TeamDetails.module.css"; -import { SettingItem } from "../../../../SettingItem/SettingItem"; -import { TextInput } from "../../../../TextInput/TextInput"; -import * as Button from "../../../../Button/"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { useState } from "react"; -import { faXmarkLarge } from "@fortawesome/pro-solid-svg-icons"; +import { TeamDetailsEdit } from "@thunderstore/cyberstorm-forms"; interface Props { teamName: string; @@ -15,42 +7,7 @@ interface Props { export function TeamDetails(props: Props) { const { teamName } = props; - const dapper = useDapper(); - const team = usePromise(dapper.getTeamDetails, [teamName]); - - const [donationLink, setDonationLink] = useState(team.donation_link ?? ""); - - return ( -
-
- -
URL
-
-
- setDonationLink(e.target.value)} - value={donationLink} - /> -
- - - - - -
-
- } - /> -
- - ); + return ; /* return ( diff --git a/packages/thunderstore-api/src/fetch/teamDetailsEdit.ts b/packages/thunderstore-api/src/fetch/teamDetailsEdit.ts new file mode 100644 index 000000000..a0d43ae99 --- /dev/null +++ b/packages/thunderstore-api/src/fetch/teamDetailsEdit.ts @@ -0,0 +1,27 @@ +import { RequestConfig } from "../index"; +import { apiFetch2 } from "../apiFetch"; + +export type teamDetailsEditMetaData = { + identifier: string; +}; + +export type teamDetailsEditApiArgs = { + donation_link: string; +}; + +export function teamDetailsEdit( + config: RequestConfig, + data: teamDetailsEditApiArgs, + metaData: teamDetailsEditMetaData +) { + const path = `api/cyberstorm/team/${metaData.identifier}/edit/`; + + return apiFetch2({ + config, + path, + request: { + method: "POST", + body: JSON.stringify(data), + }, + }); +} diff --git a/packages/thunderstore-api/src/index.ts b/packages/thunderstore-api/src/index.ts index 57b7a635d..d974aa6f4 100644 --- a/packages/thunderstore-api/src/index.ts +++ b/packages/thunderstore-api/src/index.ts @@ -17,4 +17,5 @@ export * from "./fetch/teamDetails"; export * from "./fetch/teamMembers"; export * from "./fetch/teamServiceAccounts"; export * from "./fetch/teamCreate"; +export * from "./fetch/teamDetailsEdit"; export * from "./errors"; diff --git a/packages/ts-api-react-forms/src/ApiForm.tsx b/packages/ts-api-react-forms/src/ApiForm.tsx index 9cfaf6e74..b2b44434c 100644 --- a/packages/ts-api-react-forms/src/ApiForm.tsx +++ b/packages/ts-api-react-forms/src/ApiForm.tsx @@ -14,6 +14,7 @@ export type ApiFormProps< > = { schema: Schema; endpoint: ApiEndpoint, Result>; + metaData: any; onSubmitSuccess?: (result: Result) => void; onSubmitError?: (error: Error | ApiError | unknown) => void; formProps?: Omit, "onSubmit">; @@ -23,9 +24,10 @@ export function ApiForm< Result extends object, Z extends ZodRawShape >(props: PropsWithChildren>) { - const { schema, endpoint, onSubmitSuccess, onSubmitError } = props; + const { schema, metaData, endpoint, onSubmitSuccess, onSubmitError } = props; const { form, submitHandler } = useApiForm({ schema: schema, + metaData: metaData, endpoint: endpoint, }); const onSubmit = useCallback( diff --git a/packages/ts-api-react-forms/src/index.ts b/packages/ts-api-react-forms/src/index.ts index d19267261..1735db551 100644 --- a/packages/ts-api-react-forms/src/index.ts +++ b/packages/ts-api-react-forms/src/index.ts @@ -3,3 +3,4 @@ export { getErrorFormKey, handleFormApiErrors } from "./errors"; export { useApiForm } from "./useApiForm"; export type { UseApiFormReturn, UseApiFormArgs } from "./useApiForm"; export { createTeamFormSchema } from "./schema"; +export { teamDetailsEditFormSchema } from "./schema"; diff --git a/packages/ts-api-react-forms/src/schema.ts b/packages/ts-api-react-forms/src/schema.ts index 251c266f7..5f76c30f1 100644 --- a/packages/ts-api-react-forms/src/schema.ts +++ b/packages/ts-api-react-forms/src/schema.ts @@ -5,3 +5,9 @@ export const createTeamFormSchema = z.object({ .string({ required_error: "Team name is required" }) .min(1, { message: "Team name is required" }), }); + +export const teamDetailsEditFormSchema = z.object({ + donation_link: z + .string({ required_error: "Donation link is required" }) + .min(1, { message: "Donation link is required" }), +}); diff --git a/packages/ts-api-react-forms/src/useApiForm.ts b/packages/ts-api-react-forms/src/useApiForm.ts index 8291a39e3..c88072698 100644 --- a/packages/ts-api-react-forms/src/useApiForm.ts +++ b/packages/ts-api-react-forms/src/useApiForm.ts @@ -12,6 +12,7 @@ export type UseApiFormArgs< Z extends ZodRawShape > = { schema: Schema; + metaData: any; endpoint: ApiEndpoint, Result>; }; export type UseApiFormReturn< @@ -29,7 +30,7 @@ export function useApiForm< >( args: UseApiFormArgs ): UseApiFormReturn { - const { schema, endpoint } = args; + const { schema, metaData, endpoint } = args; const apiCall = useApiCall(endpoint); const form = useForm>({ @@ -38,7 +39,7 @@ export function useApiForm< }); const submitHandler = async (data: z.infer) => { try { - return await apiCall(data); + return await apiCall(data, metaData); } catch (e) { handleFormApiErrors(e, schema, form.setError); throw e; diff --git a/packages/ts-api-react/src/useApiCall.ts b/packages/ts-api-react/src/useApiCall.ts index 6a143a9bc..ab2bcf844 100644 --- a/packages/ts-api-react/src/useApiCall.ts +++ b/packages/ts-api-react/src/useApiCall.ts @@ -3,11 +3,12 @@ import { useApiConfig } from "./useApiConfig"; export type ApiEndpoint = ( config: RequestConfig, - data: Data + data: Data, + metaData: any ) => Promise; export function useApiCall( endpoint: ApiEndpoint -): (data: Data) => Promise { +): (data: Data, metaData: any) => Promise { const apiConfig = useApiConfig(); - return (data: Data) => endpoint(apiConfig, data); + return (data: Data, metaData: any) => endpoint(apiConfig, data, metaData); }