From 539216c9393dc84fffd68a4ca03e168612239cc5 Mon Sep 17 00:00:00 2001 From: Robert Knight Date: Fri, 8 Nov 2024 12:57:09 +0000 Subject: [PATCH] Add router to group forms and placeholder page for members view Add a router to the group forms using Wouter to enable client-side transitions, and use it to enable switching between group settings and group members in the group edit forms. The "Members" page is currently just a placeholder. --- .../group-forms/components/AppRoot.tsx | 44 +++++++++++++++++++ .../components/CreateEditGroupForm.tsx | 19 ++++---- .../components/EditGroupMembersForm.tsx | 18 ++++++++ .../components/GroupFormHeader.tsx | 42 ++++++++++++++++++ .../components/forms/FormContainer.tsx | 18 ++++++++ h/static/scripts/group-forms/config.ts | 22 ++++++---- h/static/scripts/group-forms/index.tsx | 17 +------ 7 files changed, 148 insertions(+), 32 deletions(-) create mode 100644 h/static/scripts/group-forms/components/AppRoot.tsx create mode 100644 h/static/scripts/group-forms/components/EditGroupMembersForm.tsx create mode 100644 h/static/scripts/group-forms/components/GroupFormHeader.tsx create mode 100644 h/static/scripts/group-forms/components/forms/FormContainer.tsx diff --git a/h/static/scripts/group-forms/components/AppRoot.tsx b/h/static/scripts/group-forms/components/AppRoot.tsx new file mode 100644 index 00000000000..84cb65ae4ad --- /dev/null +++ b/h/static/scripts/group-forms/components/AppRoot.tsx @@ -0,0 +1,44 @@ +import { Route, Switch } from 'wouter-preact'; +import { useMemo } from 'preact/hooks'; + +import CreateEditGroupForm from './CreateEditGroupForm'; +import EditGroupMembersForm from './EditGroupMembersForm'; +import type { ConfigObject } from '../config'; +import { Config } from '../config'; + +export type AppRootProps = { + config: ConfigObject; +}; + +export default function AppRoot({ config }: AppRootProps) { + const stylesheetLinks = useMemo( + () => + config.styles.map((stylesheetURL, index) => ( + + )), + [config], + ); + + return ( + <> + {stylesheetLinks} + + + + + + + + + + + + + + + ); +} diff --git a/h/static/scripts/group-forms/components/CreateEditGroupForm.tsx b/h/static/scripts/group-forms/components/CreateEditGroupForm.tsx index 8ad8bdf969c..6a3c7defaa5 100644 --- a/h/static/scripts/group-forms/components/CreateEditGroupForm.tsx +++ b/h/static/scripts/group-forms/components/CreateEditGroupForm.tsx @@ -1,4 +1,4 @@ -import { useEffect, useId, useMemo, useState } from 'preact/hooks'; +import { useContext, useEffect, useId, useState } from 'preact/hooks'; import { Button, @@ -6,7 +6,7 @@ import { RadioGroup, useWarnOnPageUnload, } from '@hypothesis/frontend-shared'; -import { readConfig } from '../config'; +import { Config } from '../config'; import { callAPI } from '../utils/api'; import type { CreateUpdateGroupAPIRequest, @@ -15,9 +15,11 @@ import type { } from '../utils/api'; import { pluralize } from '../utils/pluralize'; import { setLocation } from '../utils/set-location'; +import FormContainer from './forms/FormContainer'; import Star from './forms/Star'; import Label from './forms/Label'; import TextField from './forms/TextField'; +import GroupFormHeader from './GroupFormHeader'; import SaveStateIcon from './SaveStateIcon'; import WarningDialog from './WarningDialog'; @@ -84,7 +86,7 @@ function GroupTypeChangeWarning({ } export default function CreateEditGroupForm() { - const config = useMemo(() => readConfig(), []); + const config = useContext(Config)!; const group = config.context.group; const [name, setName] = useState(group?.name ?? ''); @@ -217,11 +219,10 @@ export default function CreateEditGroupForm() { }; return ( -
-

- {heading} -

- + + {group && config.features.group_members && ( + + )}
-
+ ); } diff --git a/h/static/scripts/group-forms/components/EditGroupMembersForm.tsx b/h/static/scripts/group-forms/components/EditGroupMembersForm.tsx new file mode 100644 index 00000000000..e10436942f4 --- /dev/null +++ b/h/static/scripts/group-forms/components/EditGroupMembersForm.tsx @@ -0,0 +1,18 @@ +import { useContext } from 'preact/hooks'; + +import { Config } from '../config'; +import FormContainer from './forms/FormContainer'; +import GroupFormHeader from './GroupFormHeader'; + +export default function EditGroupMembersForm() { + const config = useContext(Config)!; + const group = config.context.group!; + + return ( + + +
+
Group members will appear here.
+
+ ); +} diff --git a/h/static/scripts/group-forms/components/GroupFormHeader.tsx b/h/static/scripts/group-forms/components/GroupFormHeader.tsx new file mode 100644 index 00000000000..c12b4f1eaa7 --- /dev/null +++ b/h/static/scripts/group-forms/components/GroupFormHeader.tsx @@ -0,0 +1,42 @@ +import classnames from 'classnames'; +import type { ComponentChildren } from 'preact'; +import { Link as RouterLink, useRoute } from 'wouter-preact'; + +import type { Group } from '../config'; + +type TabLinkProps = { + href: string; + children: ComponentChildren; +}; + +function TabLink({ children, href }: TabLinkProps) { + const [selected] = useRoute(href); + return ( + + {children} + + ); +} + +export type GroupFormHeaderProps = { + group: Group; +}; + +export default function GroupFormHeader({ group }: GroupFormHeaderProps) { + const editLink = `/groups/${group.pubid}/edit`; + const editMembersLinks = `/groups/${group.pubid}/edit/members`; + + return ( +
+ Settings + Members +
+ ); +} diff --git a/h/static/scripts/group-forms/components/forms/FormContainer.tsx b/h/static/scripts/group-forms/components/forms/FormContainer.tsx new file mode 100644 index 00000000000..e899c200df1 --- /dev/null +++ b/h/static/scripts/group-forms/components/forms/FormContainer.tsx @@ -0,0 +1,18 @@ +import type { ComponentChildren } from 'preact'; + +export type FormContainerProps = { + title: string; + children: ComponentChildren; +}; + +/** A container for a form with a title. */ +export default function FormContainer({ children, title }: FormContainerProps) { + return ( +
+

+ {title} +

+ {children} +
+ ); +} diff --git a/h/static/scripts/group-forms/config.ts b/h/static/scripts/group-forms/config.ts index 8140a8cacf1..3327153cba7 100644 --- a/h/static/scripts/group-forms/config.ts +++ b/h/static/scripts/group-forms/config.ts @@ -1,3 +1,4 @@ +import { createContext } from 'preact'; import type { GroupType } from './utils/api'; export type APIConfig = { @@ -6,6 +7,15 @@ export type APIConfig = { headers: Record; }; +export type Group = { + pubid: string; + name: string; + description: string; + link: string; + type: GroupType; + num_annotations: number; +}; + export type ConfigObject = { /** The URLs of the app's CSS stylesheets. */ styles: string[]; @@ -14,16 +24,10 @@ export type ConfigObject = { updateGroup: APIConfig | null; }; context: { - group: { - pubid: string; - name: string; - description: string; - link: string; - type: GroupType; - num_annotations: number; - } | null; + group: Group | null; }; features: { + group_members: boolean; group_type: boolean; }; }; @@ -32,3 +36,5 @@ export type ConfigObject = { export function readConfig(): ConfigObject { return JSON.parse(document.querySelector('.js-config')!.textContent!); } + +export const Config = createContext(null); diff --git a/h/static/scripts/group-forms/index.tsx b/h/static/scripts/group-forms/index.tsx index aaa3b2dea3d..2e9eea8d4ad 100644 --- a/h/static/scripts/group-forms/index.tsx +++ b/h/static/scripts/group-forms/index.tsx @@ -1,26 +1,13 @@ import { render } from 'preact'; -import CreateEditGroupForm from './components/CreateEditGroupForm'; +import AppRoot from './components/AppRoot'; import { readConfig } from './config'; function init() { const shadowHost = document.querySelector('#create-group-form')!; const shadowRoot = shadowHost.attachShadow({ mode: 'open' }); const config = readConfig(); - const stylesheetLinks = config.styles.map((stylesheetURL, index) => ( - - )); - render( - <> - {stylesheetLinks} - - , - shadowRoot, - ); + render(, shadowRoot); } init();