From 4cc202b62a5e8299332d1ba3d7a3ae305a9cf854 Mon Sep 17 00:00:00 2001 From: Katalina Okano Date: Sat, 17 Jul 2021 19:23:35 -0400 Subject: [PATCH] feat(Editor): make server utilities their own pages Signed-off-by: Katalina Okano --- packages/design-system/atoms/space/Space.tsx | 4 +- .../ServerUtilities.stories.tsx | 12 ++ .../ServerUtilities.styled.ts | 37 +++++ .../server-utilities/ServerUtilities.tsx | 134 +++++++++--------- .../molecules/server-utilities/index.ts | 1 + .../organisms/editor-shell/EditorShell.tsx | 63 +------- .../design-system/templates/editor/Editor.tsx | 4 +- packages/web/src/pages/editor.tsx | 23 +-- 8 files changed, 125 insertions(+), 153 deletions(-) create mode 100644 packages/design-system/molecules/server-utilities/ServerUtilities.stories.tsx create mode 100644 packages/design-system/molecules/server-utilities/ServerUtilities.styled.ts create mode 100644 packages/design-system/molecules/server-utilities/index.ts diff --git a/packages/design-system/atoms/space/Space.tsx b/packages/design-system/atoms/space/Space.tsx index 15c27a6..7321f02 100644 --- a/packages/design-system/atoms/space/Space.tsx +++ b/packages/design-system/atoms/space/Space.tsx @@ -5,10 +5,10 @@ export const Space = styled.div` height: 15px; `; -export const LinedSpace = styled.div<{ width?: number }>` +export const LinedSpace = styled.div<{ width?: number; color?: string }>` height: 7.5px; margin-top: 7.5px; - border-top: 1px solid ${palette.taupe300}; + border-top: 1px solid ${(props) => (props.color ? props.color : palette.taupe300)}; ${(props) => props.width && css` diff --git a/packages/design-system/molecules/server-utilities/ServerUtilities.stories.tsx b/packages/design-system/molecules/server-utilities/ServerUtilities.stories.tsx new file mode 100644 index 0000000..a4670f1 --- /dev/null +++ b/packages/design-system/molecules/server-utilities/ServerUtilities.stories.tsx @@ -0,0 +1,12 @@ +import { guildData } from '@roleypoly/design-system/fixtures/storyData'; +import { ServerUtilities } from './ServerUtilities'; + +export default { + title: 'Molecules/Server Utilities', + component: ServerUtilities, + args: { + guildData: guildData, + }, +}; + +export const serverUtilities = (args) => ; diff --git a/packages/design-system/molecules/server-utilities/ServerUtilities.styled.ts b/packages/design-system/molecules/server-utilities/ServerUtilities.styled.ts new file mode 100644 index 0000000..f63a9b7 --- /dev/null +++ b/packages/design-system/molecules/server-utilities/ServerUtilities.styled.ts @@ -0,0 +1,37 @@ +import { palette } from '@roleypoly/design-system/atoms/colors'; +import { transitions } from '@roleypoly/design-system/atoms/timings'; +import { text200, text400 } from '@roleypoly/design-system/atoms/typography'; +import styled from 'styled-components'; + +export const ClickaleBlock = styled.a` + display: flex; + color: unset; + text-decoration: none; + align-items: center; + padding: 0.5em; + transition: background-color ${transitions.actionable}s ease-in-out; + box-sizing: border-box; + justify-content: space-between; + max-width: 93vw; + + :hover { + background-color: ${palette.taupe300}; + } +`; + +export const Title = styled.div` + ${text400}; + /* padding: 0.15em 0; */ + + svg { + color: ${palette.taupe500}; + position: relative; + top: 2px; + } +`; + +export const Description = styled.div` + ${text200}; +`; + +export const MainSide = styled.div``; diff --git a/packages/design-system/molecules/server-utilities/ServerUtilities.tsx b/packages/design-system/molecules/server-utilities/ServerUtilities.tsx index ed9a385..a67098e 100644 --- a/packages/design-system/molecules/server-utilities/ServerUtilities.tsx +++ b/packages/design-system/molecules/server-utilities/ServerUtilities.tsx @@ -1,72 +1,74 @@ -import { palette } from '@roleypoly/design-system/atoms/colors'; -import { FaderOpacity } from '@roleypoly/design-system/atoms/fader'; -import { TextInput } from '@roleypoly/design-system/atoms/text-input'; -import { AmbientLarge, Text } from '@roleypoly/design-system/atoms/typography'; -import { MessageBox } from '@roleypoly/design-system/organisms/role-picker/RolePicker.styled'; -import { GuildData, WebhookValidationStatus } from '@roleypoly/types'; -import { GoAlert, GoInfo } from 'react-icons/go'; -import ReactTooltip from 'react-tooltip'; -import styled from 'styled-components'; +import { + ClickaleBlock, + Description, + MainSide, + Title, +} from '@roleypoly/design-system/molecules/server-utilities/ServerUtilities.styled'; +import { GuildData } from '@roleypoly/types'; +import { GoArchive, GoChevronRight, GoReport, GoShield, GoSync } from 'react-icons/go'; type Props = { - onChange: (guildData: GuildData) => void; guildData: GuildData; - validationStatus: WebhookValidationStatus | null; }; -export const ServerUtilities = (props: Props) => { - return ( - - - (optional) Webhook URL for Audit Logging{' '} - - - - props.onChange({ ...props.guildData, auditLogWebhook: event.target.value }) - } - /> - - - - - - ); -}; +const Utility = (props: { + link: string; + title: React.ReactNode; + description: string; +}) => ( + + + {props.title} + {props.description} + +
+ +
+
+); -const ValidationStatus = (props: Pick) => { - switch (props.validationStatus) { - case WebhookValidationStatus.NotDiscordURL: - return ( - - URL must be to a Discord webhook, starting with - "https://discord.com/api/webhooks/". - - ); - case WebhookValidationStatus.NotSameGuild: - return ( - - Webhook must be in the same guild you are currently editing. - - ); - case WebhookValidationStatus.DoesNotExist: - return ( - - This webhook doesn't exist. - - ); - default: - return  ; - } -}; - -const Alert = styled(GoAlert)` - color: ${palette.red400}; - position: relative; - top: 2px; -`; +export const ServerUtilities = (props: Props) => ( +
+ {/* Server Utilities */} + + +   Access Control + + } + description="Set up who can use Roleypoly in your server" + link={`/s/${props.guildData.id}/edit/access-control`} + /> + + +   Audit Logging + + } + description="Setup audit logging via a Discord webhook" + link={`/s/${props.guildData.id}/edit/audit-logging`} + /> + + +   Import from Roleypoly Legacy + + } + description="Used Roleypoly before and don't see your categories?" + link={`/s/${props.guildData.id}/edit/import-from-legacy`} + /> + + +   Manage your Data + + } + description="Export or delete all of your Roleypoly data." + link={`/s/${props.guildData.id}/edit/data`} + /> +
+); diff --git a/packages/design-system/molecules/server-utilities/index.ts b/packages/design-system/molecules/server-utilities/index.ts new file mode 100644 index 0000000..2020033 --- /dev/null +++ b/packages/design-system/molecules/server-utilities/index.ts @@ -0,0 +1 @@ +export * from './ServerUtilities'; diff --git a/packages/design-system/organisms/editor-shell/EditorShell.tsx b/packages/design-system/organisms/editor-shell/EditorShell.tsx index 0258b00..693b163 100644 --- a/packages/design-system/organisms/editor-shell/EditorShell.tsx +++ b/packages/design-system/organisms/editor-shell/EditorShell.tsx @@ -5,12 +5,7 @@ import { ServerUtilities } from '@roleypoly/design-system/molecules/server-utili import { SecondaryEditing } from '@roleypoly/design-system/organisms/masthead'; import { Container } from '@roleypoly/design-system/organisms/role-picker/RolePicker.styled'; import { ServerCategoryEditor } from '@roleypoly/design-system/organisms/server-category-editor'; -import { - Category, - GuildData, - PresentableGuild, - WebhookValidationStatus, -} from '@roleypoly/types'; +import { Category, PresentableGuild } from '@roleypoly/types'; import deepEqual from 'deep-equal'; import React from 'react'; @@ -19,26 +14,17 @@ export type EditorShellProps = { onGuildChange?: (guild: PresentableGuild) => void; onCategoryChange?: (category: Category) => void; onMessageChange?: (message: PresentableGuild['data']['message']) => void; - errors: { - webhookValidation: WebhookValidationStatus; - }; }; export const EditorShell = (props: EditorShellProps) => { const [guild, setGuild] = React.useState(props.guild); - const [errors, setErrors] = React.useState(props.errors); React.useEffect(() => { setGuild(props.guild); }, [props.guild]); - React.useEffect(() => { - setErrors(props.errors); - }, [props.errors]); - const reset = () => { setGuild(props.guild); - setErrors({ webhookValidation: WebhookValidationStatus.Ok }); }; const replaceCategories = (categories: Category[]) => { @@ -53,12 +39,6 @@ export const EditorShell = (props: EditorShellProps) => { }); }; - const updateGuildData = (data: PresentableGuild['data']) => { - setGuild((currentGuild) => { - return { ...currentGuild, data }; - }); - }; - const doSubmit = () => { props.onGuildChange?.(guild); }; @@ -87,47 +67,8 @@ export const EditorShell = (props: EditorShellProps) => { - + ); }; - -const validateWebhook = ( - webhook: GuildData['auditLogWebhook'], - validationStatus: WebhookValidationStatus -) => { - if (!webhook) { - return WebhookValidationStatus.NoneSet; - } - - try { - const url = new URL(webhook); - - if ( - url.hostname !== 'discord.com' || - url.protocol !== 'https:' || - url.pathname.startsWith('api/webhooks/') - ) { - return WebhookValidationStatus.NotDiscordURL; - } - } catch (e) { - return WebhookValidationStatus.Ok; - } - - if ( - validationStatus !== WebhookValidationStatus.Ok && - validationStatus !== WebhookValidationStatus.NoneSet - ) { - return validationStatus; - } - - return WebhookValidationStatus.Ok; -}; diff --git a/packages/design-system/templates/editor/Editor.tsx b/packages/design-system/templates/editor/Editor.tsx index 36d76d3..6e6169c 100644 --- a/packages/design-system/templates/editor/Editor.tsx +++ b/packages/design-system/templates/editor/Editor.tsx @@ -11,9 +11,7 @@ export const EditorTemplate = ( props; return ( - + ); }; - -export type EditorErrors = EditorShellProps['errors']; diff --git a/packages/web/src/pages/editor.tsx b/packages/web/src/pages/editor.tsx index c123568..5dfa9d6 100644 --- a/packages/web/src/pages/editor.tsx +++ b/packages/web/src/pages/editor.tsx @@ -1,11 +1,10 @@ import { navigate, Redirect } from '@reach/router'; -import { EditorErrors, EditorTemplate } from '@roleypoly/design-system/templates/editor'; +import { EditorTemplate } from '@roleypoly/design-system/templates/editor'; import { GenericLoadingTemplate } from '@roleypoly/design-system/templates/generic-loading'; import { GuildDataUpdate, PresentableGuild, UserGuildPermissions, - WebhookValidationStatus, } from '@roleypoly/types'; import * as React from 'react'; import { useAppShellProps } from '../contexts/app-shell/AppShellContext'; @@ -26,9 +25,6 @@ const Editor = (props: EditorProps) => { const [guild, setGuild] = React.useState(null); const [pending, setPending] = React.useState(false); - const [errors, setErrors] = React.useState({ - webhookValidation: WebhookValidationStatus.Ok, - }); React.useEffect(() => { const shouldPullUncached = (): boolean => { @@ -104,28 +100,13 @@ const Editor = (props: EditorProps) => { navigate(`/s/${props.serverID}`); } - if (response.status === 400) { - const error = await response.json(); - if (error.data.what === 'webhookValidationStatus') { - setErrors((errors) => ({ - ...errors, - webhookValidation: error.data.webhookValidationStatus, - })); - } - } - setPending(false); }; return ( <> - <EditorTemplate - {...appShellProps} - guild={guild} - onGuildChange={onGuildChange} - errors={errors} - /> + <EditorTemplate {...appShellProps} guild={guild} onGuildChange={onGuildChange} /> </> ); };