-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* style(colors): add danger for icon * feat(api-service): add collaborator API service methods * feat(hooks): add collaborator hooks * feat: add CollaboratorModal * feat: add Dashboard layout This Dashboard layout contains the CollaboratorModal * feat(storybook): add stories for CollaboratorModal * fix: import order * chore: remove duplicate collaboratorData * chore: only import types * chore: replace button with loadingbutton * chore: remove unused import * fix: also disable button if field is empty * fix: wrong redirect path * feat: make link open in new tab * feat: handle enter key for input * temp create special route for collaborators * ref(collaborators): refactor to remove shared props from context (#1076) * refactor(collaborators): refactors collaborators to remove context * fix(removecollaborator): renamed variable for clarity * chore(cøllaboratorhooks): remove extra imports * chore(collaboratormodal): rename variable for clarity * fix(mainsubmodal): add rudimentary validation * refactor(collaboratormodal): shift constant to own file * chore(collaboratormodal): misc fixes * chore(loadingbutton): add code block * refactor(ack submodal): remove moadl body * refactor(removecollaboratorsubmodal): pass user and onDeleteComplete as props * refactor(collaboratormodal): refactor to manage state between deletion/mainmodal * refactor(mainsubmodal): shift unnecessary state downwards into the main modal * chore(utils): tweak apiDataBuilder to be slightly more powerful * chore(collab modal stories): tweak stories to work with api * chore(collaboratormodal): rename subfolder to components * chore(constants): removed unused stuff * refactor(collaborators types): shift collaborator types to types folder * chore(collaboratorservice): add types to methods * chore(collaboratorhooks): add types to hooks * chore(mocks): update mocks to fit new typings * chore(mainsubmodal): update to fit new types * chore(collaborator hooks): shift into own files for ease of discovery * chore(types): shift collaborator to error and rename * chore(dashboard): edit dashboard for testing * chore(collaboratorhooks): update error import * refactor(mainsubmodal): add loading state and fix reset * refactor(ack submodal): add isloading prop * refactor(collaboartor): add loading stae; update import * chore(usedeletecollaboratorhook): update erro type * fix(collaboratormodal): prevent useres being stuck on delete * fix(uselistcollaboratorshook): transform data from be into shape * fix(mainsubmodal): disable button if field empty * chore(mainsubmodal): convert units to rem * fix(mainsubmodal): clean up state on modal close * chore(mainsubmodal): remove unused variables * chore(mainsubmodal): remove multiple calls to function * chore(collaboratormodal): fix stories * fix(mainsubmodal): fixed text sizing and add placeholder * fix(collaborator): fixed story typing for constants * chore(mainsubmodal): update text styling Co-authored-by: seaerchin <[email protected]>
- Loading branch information
1 parent
10eb8ea
commit 7e51399
Showing
24 changed files
with
962 additions
and
13 deletions.
There are no files selected for viewing
123 changes: 123 additions & 0 deletions
123
src/components/CollaboratorModal/CollaboratorModal.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import { Button, useDisclosure } from "@chakra-ui/react" | ||
import { ComponentMeta, ComponentStory } from "@storybook/react" | ||
import { CollaboratorModal } from "components/CollaboratorModal/index" | ||
import { MemoryRouter, Route } from "react-router-dom" | ||
|
||
import { MOCK_COLLABORATORS, MOCK_USER } from "mocks/constants" | ||
import { handlers } from "mocks/handlers" | ||
import { | ||
buildCollaboratorData, | ||
buildCollaboratorRoleData, | ||
buildContributor, | ||
buildLoginData, | ||
buildRemoveContributor, | ||
} from "mocks/utils" | ||
|
||
const collaboratorModalMeta = { | ||
title: "Components/CollaboratorModal", | ||
component: CollaboratorModal, | ||
parameters: { | ||
// Set delay so mock API requests will get resolved and the UI will render properly | ||
chromatic: { delay: 500 }, | ||
msw: { | ||
handlers, | ||
}, | ||
}, | ||
decorators: [ | ||
(Story) => { | ||
return ( | ||
<MemoryRouter initialEntries={["/sites/:siteName/dashboard"]}> | ||
<Route path="/sites/:siteName/dashboard"> | ||
<Story /> | ||
</Route> | ||
</MemoryRouter> | ||
) | ||
}, | ||
], | ||
} as ComponentMeta<typeof CollaboratorModal> | ||
|
||
// TODO!: add stories for the submodals | ||
// the sub modals won't show up on chromatic when changes are made at present. | ||
const Template: ComponentStory<typeof CollaboratorModal> = () => { | ||
const props = useDisclosure({ defaultIsOpen: true }) | ||
return ( | ||
<> | ||
<Button onClick={props.onOpen}>Open collaborators</Button> | ||
<CollaboratorModal {...props} /> | ||
</> | ||
) | ||
} | ||
|
||
export const AdminMain = Template.bind({}) | ||
AdminMain.parameters = { | ||
msw: { | ||
handlers: [ | ||
...handlers, | ||
buildRemoveContributor(null), | ||
buildLoginData(MOCK_USER), | ||
buildCollaboratorData({ | ||
collaborators: [ | ||
// Email override so that the modal can display the "(You)" text depending on | ||
// the LoggedInUser | ||
{ ...MOCK_COLLABORATORS.ADMIN_2, email: MOCK_USER.email }, | ||
MOCK_COLLABORATORS.ADMIN_1, | ||
MOCK_COLLABORATORS.CONTRIBUTOR_1, | ||
MOCK_COLLABORATORS.CONTRIBUTOR_2, | ||
], | ||
}), | ||
buildCollaboratorRoleData({ role: "ADMIN" }), | ||
buildContributor(), | ||
], | ||
}, | ||
} | ||
|
||
export const ContributorMain = Template.bind({}) | ||
ContributorMain.parameters = { | ||
msw: { | ||
handlers: [ | ||
...handlers, | ||
buildLoginData(MOCK_USER), | ||
buildCollaboratorData({ | ||
collaborators: [ | ||
MOCK_COLLABORATORS.ADMIN_2, | ||
MOCK_COLLABORATORS.ADMIN_1, | ||
// Email override so that the modal can display the "(You)" text depending on | ||
// the LoggedInUser | ||
{ | ||
...MOCK_COLLABORATORS.CONTRIBUTOR_1, | ||
email: MOCK_USER.email, | ||
// Setting lastLoggedIn as now since that must be true | ||
// because the user is seeing this modal | ||
lastLoggedIn: new Date().toString(), | ||
}, | ||
MOCK_COLLABORATORS.CONTRIBUTOR_2, | ||
], | ||
}), | ||
buildCollaboratorRoleData({ role: "CONTRIBUTOR" }), | ||
], | ||
}, | ||
} | ||
|
||
export const AdminAddContributor = Template.bind({}) | ||
AdminAddContributor.parameters = { | ||
msw: { | ||
handlers: [ | ||
...handlers, | ||
buildLoginData(MOCK_USER), | ||
buildRemoveContributor(null), | ||
buildCollaboratorData({ | ||
collaborators: [ | ||
// Email override so that the modal can display the "(You)" text depending on | ||
// the LoggedInUser | ||
{ ...MOCK_COLLABORATORS.ADMIN_2, email: MOCK_USER.email }, | ||
MOCK_COLLABORATORS.ADMIN_1, | ||
MOCK_COLLABORATORS.CONTRIBUTOR_1, | ||
MOCK_COLLABORATORS.CONTRIBUTOR_2, | ||
], | ||
}), | ||
buildCollaboratorRoleData({ role: "ADMIN" }), | ||
buildContributor(true), | ||
], | ||
}, | ||
} | ||
export default collaboratorModalMeta |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { ModalProps } from "@chakra-ui/react" | ||
import { | ||
MainSubmodal, | ||
RemoveCollaboratorSubmodal, | ||
} from "components/CollaboratorModal/components" | ||
import { useState } from "react" | ||
|
||
import { useLoginContext } from "contexts/LoginContext" | ||
|
||
import useRedirectHook from "hooks/useRedirectHook" | ||
|
||
import { Collaborator } from "types/collaborators" | ||
|
||
// eslint-disable-next-line import/prefer-default-export | ||
export const CollaboratorModal = ( | ||
props: Omit<ModalProps, "children"> | ||
): JSX.Element => { | ||
const [deleteCollaboratorTarget, setDeleteCollaboratorTarget] = useState< | ||
Collaborator | undefined | ||
>(undefined) | ||
const { onCloseComplete } = props | ||
const [showDelete, setShowDelete] = useState(false) | ||
const { email } = useLoginContext() | ||
const isUserDeletingThemselves = email === deleteCollaboratorTarget?.email | ||
const { setRedirectToPage } = useRedirectHook() | ||
|
||
return showDelete && deleteCollaboratorTarget ? ( | ||
<RemoveCollaboratorSubmodal | ||
{...props} | ||
userToDelete={deleteCollaboratorTarget} | ||
onCloseComplete={() => { | ||
setShowDelete(false) | ||
onCloseComplete?.() | ||
}} | ||
onDeleteComplete={() => { | ||
setShowDelete(false) | ||
if (isUserDeletingThemselves) { | ||
setRedirectToPage(`/sites`) | ||
} | ||
}} | ||
/> | ||
) : ( | ||
<MainSubmodal | ||
{...props} | ||
onDelete={(user) => { | ||
setShowDelete(true) | ||
setDeleteCollaboratorTarget(user) | ||
}} | ||
/> | ||
) | ||
} |
94 changes: 94 additions & 0 deletions
94
src/components/CollaboratorModal/components/AcknowledgementSubmodal.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { | ||
Text, | ||
UnorderedList, | ||
ListItem, | ||
Stack, | ||
useModalContext, | ||
} from "@chakra-ui/react" | ||
import { Button, Link, Checkbox } from "@opengovsg/design-system-react" | ||
import { useFormContext } from "react-hook-form" | ||
|
||
import { TEXT_FONT_SIZE } from "../constants" | ||
|
||
const TERMS_OF_USE_LINK = "https://v2.isomer.gov.sg" // TODO: Update this when we get it | ||
|
||
export const AcknowledgementSubmodalContent = ({ | ||
isLoading, | ||
}: { | ||
isLoading: boolean | ||
}): JSX.Element => { | ||
const { watch, register, getValues } = useFormContext() | ||
const isAcknowledged = watch("isAcknowledged") | ||
const newCollaboratorEmail = getValues("newCollaboratorEmail") | ||
|
||
const { onClose } = useModalContext() | ||
|
||
return ( | ||
<> | ||
<Text fontSize={TEXT_FONT_SIZE}> | ||
<Text as="span">You are adding</Text> | ||
<Text color="primary.500" as="span"> | ||
{" "} | ||
{newCollaboratorEmail}{" "} | ||
</Text> | ||
<Text as="span">as a collaborator to your site.</Text> | ||
</Text> | ||
<br /> | ||
<Text fontSize={TEXT_FONT_SIZE}> | ||
<Text as="span">This user</Text> | ||
<Text as="b"> will be able to </Text> | ||
<Text as="span"> | ||
{" "} | ||
edit site content and publish it with the approval of a Site Admin, | ||
but{" "} | ||
</Text> | ||
<Text as="b"> will not be able to </Text> | ||
<Text as="span"> add/remove collaborators, or approve changes.</Text> | ||
</Text> | ||
<br /> | ||
<Text fontSize={TEXT_FONT_SIZE}> | ||
<Text as="span"> | ||
Site Admins and their respective agencies or healthcare institutions | ||
are responsible for: | ||
</Text> | ||
</Text> | ||
<Text fontSize={TEXT_FONT_SIZE}> | ||
<UnorderedList ml="24px"> | ||
<ListItem> | ||
The users they authorise to edit their sites in any manner or | ||
capacity | ||
</ListItem> | ||
<ListItem>All the content published on the sites</ListItem> | ||
</UnorderedList> | ||
</Text> | ||
<br /> | ||
<Text fontSize={TEXT_FONT_SIZE}> | ||
<Text as="span"> | ||
GovTech will not be held liable for content published by any user that | ||
has been granted access/allowed to retain access by a Site Admin. | ||
</Text> | ||
</Text> | ||
<br /> | ||
<Checkbox {...register("isAcknowledged")}> | ||
<Text color="text.body" fontSize="16px"> | ||
<Text as="span">I agree to Isomer‘s</Text>{" "} | ||
<Link href={TERMS_OF_USE_LINK} target="_blank"> | ||
Terms of Use | ||
</Link> | ||
</Text> | ||
</Checkbox> | ||
<Stack spacing={4} direction="row" justify="right"> | ||
<Button variant="clear" color="secondary" onClick={onClose}> | ||
Cancel | ||
</Button> | ||
<Button | ||
isDisabled={!isAcknowledged} | ||
type="submit" | ||
isLoading={isLoading} | ||
> | ||
Continue | ||
</Button> | ||
</Stack> | ||
</> | ||
) | ||
} |
Oops, something went wrong.