From f25cd93012d898f1ac09730cc906237e5c3a7ec5 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Fri, 16 Feb 2024 10:22:18 -0800 Subject: [PATCH] Prevent admin from resetting their own role. --- src/app/(main)/NavBar.module.css | 1 + src/app/(main)/UpdateNotice.tsx | 1 - .../users/{ => [userId]}/UserEditForm.tsx | 35 ++++++++++--------- .../settings/users/[userId]/UserPage.tsx | 7 +++- .../settings/users/[userId]/UserProvider.tsx | 24 +++++++++++++ .../settings/users/[userId]/UserSettings.tsx | 22 ++++++------ .../[websiteId]/realtime/Realtime.module.css | 2 +- .../websites/[websiteId]/reports/page.tsx | 2 +- src/components/input/TeamsButton.module.css | 1 + src/components/input/TeamsButton.tsx | 2 +- 10 files changed, 66 insertions(+), 31 deletions(-) rename src/app/(main)/settings/users/{ => [userId]}/UserEditForm.tsx (65%) create mode 100644 src/app/(main)/settings/users/[userId]/UserProvider.tsx diff --git a/src/app/(main)/NavBar.module.css b/src/app/(main)/NavBar.module.css index 20db4c62..c7bd5ed9 100644 --- a/src/app/(main)/NavBar.module.css +++ b/src/app/(main)/NavBar.module.css @@ -7,6 +7,7 @@ background: var(--base75); border-bottom: 1px solid var(--base300); padding: 0 20px; + z-index: 200; } .logo { diff --git a/src/app/(main)/UpdateNotice.tsx b/src/app/(main)/UpdateNotice.tsx index c56d3ce4..54ad05c9 100644 --- a/src/app/(main)/UpdateNotice.tsx +++ b/src/app/(main)/UpdateNotice.tsx @@ -1,4 +1,3 @@ -'use client'; import { useEffect, useCallback, useState } from 'react'; import { createPortal } from 'react-dom'; import { Button } from 'react-basics'; diff --git a/src/app/(main)/settings/users/UserEditForm.tsx b/src/app/(main)/settings/users/[userId]/UserEditForm.tsx similarity index 65% rename from src/app/(main)/settings/users/UserEditForm.tsx rename to src/app/(main)/settings/users/[userId]/UserEditForm.tsx index d904be47..369b4ff2 100644 --- a/src/app/(main)/settings/users/UserEditForm.tsx +++ b/src/app/(main)/settings/users/[userId]/UserEditForm.tsx @@ -8,13 +8,13 @@ import { TextField, SubmitButton, PasswordField, - useToasts, } from 'react-basics'; -import { useApi, useMessages } from 'components/hooks'; +import { useApi, useLogin, useMessages } from 'components/hooks'; import { ROLES } from 'lib/constants'; -import { useRef } from 'react'; +import { useContext, useRef } from 'react'; +import { UserContext } from './UserProvider'; -export function UserEditForm({ userId, data }: { userId: string; data: object }) { +export function UserEditForm({ userId, onSave }: { userId: string; onSave?: () => void }) { const { formatMessage, labels, messages } = useMessages(); const { post, useMutation } = useApi(); const { mutate, error } = useMutation({ @@ -29,13 +29,14 @@ export function UserEditForm({ userId, data }: { userId: string; data: object }) }) => post(`/users/${userId}`, { username, password, role }), }); const ref = useRef(null); - const { showToast } = useToasts(); + const user = useContext(UserContext); + const { user: login } = useLogin(); const handleSubmit = async (data: any) => { mutate(data, { onSuccess: async () => { - showToast({ message: formatMessage(messages.saved), variant: 'success' }); ref.current.reset(data); + onSave?.(); }, }); }; @@ -53,7 +54,7 @@ export function UserEditForm({ userId, data }: { userId: string; data: object }) }; return ( -
+ @@ -69,15 +70,17 @@ export function UserEditForm({ userId, data }: { userId: string; data: object }) - - - - {formatMessage(labels.viewOnly)} - {formatMessage(labels.user)} - {formatMessage(labels.administrator)} - - - + {user.id !== login.id && ( + + + + {formatMessage(labels.viewOnly)} + {formatMessage(labels.user)} + {formatMessage(labels.administrator)} + + + + )} {formatMessage(labels.save)} diff --git a/src/app/(main)/settings/users/[userId]/UserPage.tsx b/src/app/(main)/settings/users/[userId]/UserPage.tsx index 285433eb..50d5ab7e 100644 --- a/src/app/(main)/settings/users/[userId]/UserPage.tsx +++ b/src/app/(main)/settings/users/[userId]/UserPage.tsx @@ -1,6 +1,11 @@ 'use client'; import UserSettings from './UserSettings'; +import UserProvider from './UserProvider'; export default function ({ userId }: { userId: string }) { - return ; + return ( + + + + ); } diff --git a/src/app/(main)/settings/users/[userId]/UserProvider.tsx b/src/app/(main)/settings/users/[userId]/UserProvider.tsx new file mode 100644 index 00000000..b289fca0 --- /dev/null +++ b/src/app/(main)/settings/users/[userId]/UserProvider.tsx @@ -0,0 +1,24 @@ +import { createContext, ReactNode, useEffect } from 'react'; +import { useModified, useUser } from 'components/hooks'; +import { Loading } from 'react-basics'; + +export const UserContext = createContext(null); + +export function UserProvider({ userId, children }: { userId: string; children: ReactNode }) { + const { modified } = useModified(`user:${userId}`); + const { data: user, isFetching, isLoading, refetch } = useUser(userId); + + useEffect(() => { + if (modified) { + refetch(); + } + }, [modified]); + + if (isFetching && isLoading) { + return ; + } + + return {children}; +} + +export default UserProvider; diff --git a/src/app/(main)/settings/users/[userId]/UserSettings.tsx b/src/app/(main)/settings/users/[userId]/UserSettings.tsx index 50a36487..1ea663f5 100644 --- a/src/app/(main)/settings/users/[userId]/UserSettings.tsx +++ b/src/app/(main)/settings/users/[userId]/UserSettings.tsx @@ -1,19 +1,21 @@ -import { Key, useState } from 'react'; -import { Item, Loading, Tabs } from 'react-basics'; +import { Key, useContext, useState } from 'react'; +import { Item, Tabs, useToasts } from 'react-basics'; import Icons from 'components/icons'; -import UserEditForm from '../UserEditForm'; +import UserEditForm from './UserEditForm'; import PageHeader from 'components/layout/PageHeader'; -import { useMessages, useUser } from 'components/hooks'; +import { useMessages } from 'components/hooks'; import UserWebsites from './UserWebsites'; +import { UserContext } from './UserProvider'; export function UserSettings({ userId }: { userId: string }) { - const { formatMessage, labels } = useMessages(); + const { formatMessage, labels, messages } = useMessages(); const [tab, setTab] = useState('details'); - const { data: user, isLoading } = useUser(userId, { gcTime: 0 }); + const user = useContext(UserContext); + const { showToast } = useToasts(); - if (isLoading) { - return ; - } + const handleSave = () => { + showToast({ message: formatMessage(messages.saved), variant: 'success' }); + }; return ( <> @@ -22,7 +24,7 @@ export function UserSettings({ userId }: { userId: string }) { {formatMessage(labels.details)} {formatMessage(labels.websites)} - {tab === 'details' && } + {tab === 'details' && } {tab === 'websites' && } ); diff --git a/src/app/(main)/websites/[websiteId]/realtime/Realtime.module.css b/src/app/(main)/websites/[websiteId]/realtime/Realtime.module.css index 4abf0a4e..465be551 100644 --- a/src/app/(main)/websites/[websiteId]/realtime/Realtime.module.css +++ b/src/app/(main)/websites/[websiteId]/realtime/Realtime.module.css @@ -11,6 +11,6 @@ top: 0; background: var(--base50); border-bottom: 1px solid var(--base300); - z-index: var(--z-index-overlay); + z-index: 1; padding: 10px 0; } diff --git a/src/app/(main)/websites/[websiteId]/reports/page.tsx b/src/app/(main)/websites/[websiteId]/reports/page.tsx index 64353b59..7726a2cd 100644 --- a/src/app/(main)/websites/[websiteId]/reports/page.tsx +++ b/src/app/(main)/websites/[websiteId]/reports/page.tsx @@ -1,5 +1,5 @@ import WebsiteReportsPage from './WebsiteReportsPage'; -export default function WebsiteReportsPage({ params: { websiteId } }) { +export default function ({ params: { websiteId } }) { return ; } diff --git a/src/components/input/TeamsButton.module.css b/src/components/input/TeamsButton.module.css index 7b4d8c7b..2b1fd549 100644 --- a/src/components/input/TeamsButton.module.css +++ b/src/components/input/TeamsButton.module.css @@ -4,6 +4,7 @@ .menu { background: var(--base50); + min-width: 260px; } .heading { diff --git a/src/components/input/TeamsButton.tsx b/src/components/input/TeamsButton.tsx index c7fc535a..ae995aca 100644 --- a/src/components/input/TeamsButton.tsx +++ b/src/components/input/TeamsButton.tsx @@ -29,7 +29,7 @@ export function TeamsButton({ teamId }: { teamId: string }) { {(close: () => void) => ( - +
{formatMessage(labels.myAccount)}