From a14e11bae2c8581e4b254049c06da2f590edf3c5 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 4 Oct 2023 01:46:00 -0700 Subject: [PATCH] Updated add team website form. --- src/app/(main)/reports/ReportsList.js | 12 ++--- .../teams/{TeamsList.js => TeamsDataTable.js} | 15 ++++-- .../settings/teams/[id]/TeamAddWebsiteForm.js | 51 ++++++++----------- .../(main)/settings/teams/[id]/TeamMembers.js | 4 +- .../{ => [id]}/TeamWebsiteRemoveButton.js | 2 +- .../settings/teams/[id]/TeamWebsites.js | 14 ++--- .../settings/teams/[id]/TeamWebsitesTable.js | 14 ++--- src/app/(main)/settings/teams/page.js | 4 +- .../users/{UsersList.js => UsersDataTable.js} | 9 ++-- src/app/(main)/settings/users/page.tsx | 4 +- .../{Websites.js => WebsitesDataTable.js} | 38 +++++++++----- .../(main)/settings/websites/WebsitesTable.js | 30 +++++++---- src/app/(main)/settings/websites/page.js | 4 +- src/app/(main)/websites/WebsitesBrowse.js | 2 +- src/components/common/DataTable.tsx | 41 ++++++++------- src/components/hooks/useFilterQuery.ts | 26 +++++----- src/index.ts | 6 +-- src/lib/middleware.ts | 2 +- 18 files changed, 149 insertions(+), 129 deletions(-) rename src/app/(main)/settings/teams/{TeamsList.js => TeamsDataTable.js} (54%) rename src/app/(main)/settings/teams/{ => [id]}/TeamWebsiteRemoveButton.js (88%) rename src/app/(main)/settings/users/{UsersList.js => UsersDataTable.js} (62%) rename src/app/(main)/settings/websites/{Websites.js => WebsitesDataTable.js} (59%) diff --git a/src/app/(main)/reports/ReportsList.js b/src/app/(main)/reports/ReportsList.js index dc2b9f2b..44da4fac 100644 --- a/src/app/(main)/reports/ReportsList.js +++ b/src/app/(main)/reports/ReportsList.js @@ -7,30 +7,30 @@ import DataTable from 'components/common/DataTable'; function useReports() { const { get, del, useMutation } = useApi(); const { mutate } = useMutation(reportId => del(`/reports/${reportId}`)); - const reports = useFilterQuery(['reports'], params => get(`/reports`, params)); + const queryResult = useFilterQuery(['reports'], params => get(`/reports`, params)); const deleteReport = id => { mutate(id, { onSuccess: () => { - reports.refetch(); + queryResult.refetch(); }, }); }; - return { reports, deleteReport }; + return { queryResult, deleteReport }; } export default function ReportsList() { - const { reports, deleteReport } = useReports(); + const { queryResult, deleteReport } = useReports(); const handleDelete = async (id, callback) => { await deleteReport(id); - await reports.refetch(); + await queryResult.refetch(); callback?.(); }; return ( - + {({ data }) => } ); diff --git a/src/app/(main)/settings/teams/TeamsList.js b/src/app/(main)/settings/teams/TeamsDataTable.js similarity index 54% rename from src/app/(main)/settings/teams/TeamsList.js rename to src/app/(main)/settings/teams/TeamsDataTable.js index 1983ceae..41287f48 100644 --- a/src/app/(main)/settings/teams/TeamsList.js +++ b/src/app/(main)/settings/teams/TeamsDataTable.js @@ -4,16 +4,21 @@ import TeamsTable from 'app/(main)/settings/teams/TeamsTable'; import useApi from 'components/hooks/useApi'; import useFilterQuery from 'components/hooks/useFilterQuery'; -export function TeamsList() { +export function TeamsDataTable() { const { get } = useApi(); - const filterQuery = useFilterQuery(['teams'], params => { + const queryResult = useFilterQuery(['teams'], params => { return get(`/teams`, { ...params, }); }); - const { getProps } = filterQuery; - return {({ data }) => }; + return ( + + {({ data }) => { + return ; + }} + + ); } -export default TeamsList; +export default TeamsDataTable; diff --git a/src/app/(main)/settings/teams/[id]/TeamAddWebsiteForm.js b/src/app/(main)/settings/teams/[id]/TeamAddWebsiteForm.js index 503ad111..a2d0faf0 100644 --- a/src/app/(main)/settings/teams/[id]/TeamAddWebsiteForm.js +++ b/src/app/(main)/settings/teams/[id]/TeamAddWebsiteForm.js @@ -1,22 +1,20 @@ import useApi from 'components/hooks/useApi'; -import { useRef, useState } from 'react'; -import { Button, Dropdown, Form, FormButtons, FormRow, Item, SubmitButton } from 'react-basics'; -import WebsiteTags from '../WebsiteTags'; +import { useState } from 'react'; +import { Button, Form, FormButtons, GridColumn, Loading, SubmitButton, Toggle } from 'react-basics'; import useMessages from 'components/hooks/useMessages'; +import WebsitesDataTable from '../../websites/WebsitesDataTable'; export function TeamAddWebsiteForm({ teamId, onSave, onClose }) { const { formatMessage, labels } = useMessages(); const { get, post, useQuery, useMutation } = useApi(); const { mutate, error } = useMutation(data => post(`/teams/${teamId}/websites`, data)); const { data: websites } = useQuery(['websites'], () => get('/websites')); - const [newWebsites, setNewWebsites] = useState([]); - const formRef = useRef(); - + const [selected, setSelected] = useState([]); const hasData = websites && websites.data.length > 0; const handleSubmit = () => { mutate( - { websiteIds: newWebsites }, + { websiteIds: selected }, { onSuccess: async () => { onSave(); @@ -26,34 +24,29 @@ export function TeamAddWebsiteForm({ teamId, onSave, onClose }) { ); }; - const handleAddWebsite = value => { - if (!newWebsites.some(a => a === value)) { - const nextValue = [...newWebsites]; - - nextValue.push(value); - - setNewWebsites(nextValue); - } - }; - - const handleRemoveWebsite = value => { - const newValue = newWebsites.filter(a => a !== value); - - setNewWebsites(newValue); + const handleSelect = id => { + setSelected(state => (state.includes(id) ? state.filter(n => n !== id) : state.concat(id))); }; return ( <> + {!hasData && } {hasData && ( -
- - - {({ id, name }) => {name}} - - - + + + + {row => ( + + )} + + - + {formatMessage(labels.addWebsite)} diff --git a/src/app/(main)/settings/teams/[id]/TeamMembers.js b/src/app/(main)/settings/teams/[id]/TeamMembers.js index f061d22d..a5a0d197 100644 --- a/src/app/(main)/settings/teams/[id]/TeamMembers.js +++ b/src/app/(main)/settings/teams/[id]/TeamMembers.js @@ -5,7 +5,7 @@ import DataTable from 'components/common/DataTable'; export function TeamMembers({ teamId, readOnly }) { const { get } = useApi(); - const { getProps } = useFilterQuery( + const queryResult = useFilterQuery( ['team:users', teamId], params => { return get(`/teams/${teamId}/users`, { @@ -17,7 +17,7 @@ export function TeamMembers({ teamId, readOnly }) { return ( <> - + {({ data }) => } diff --git a/src/app/(main)/settings/teams/TeamWebsiteRemoveButton.js b/src/app/(main)/settings/teams/[id]/TeamWebsiteRemoveButton.js similarity index 88% rename from src/app/(main)/settings/teams/TeamWebsiteRemoveButton.js rename to src/app/(main)/settings/teams/[id]/TeamWebsiteRemoveButton.js index c0ddf95c..532e5321 100644 --- a/src/app/(main)/settings/teams/TeamWebsiteRemoveButton.js +++ b/src/app/(main)/settings/teams/[id]/TeamWebsiteRemoveButton.js @@ -19,7 +19,7 @@ export function TeamWebsiteRemoveButton({ teamId, websiteId, onSave }) { }; return ( - handleRemoveTeamMember()} isLoading={isLoading}> + handleRemoveTeamMember()} isLoading={isLoading}> diff --git a/src/app/(main)/settings/teams/[id]/TeamWebsites.js b/src/app/(main)/settings/teams/[id]/TeamWebsites.js index 5f13027e..e7786429 100644 --- a/src/app/(main)/settings/teams/[id]/TeamWebsites.js +++ b/src/app/(main)/settings/teams/[id]/TeamWebsites.js @@ -11,7 +11,7 @@ export function TeamWebsites({ teamId }) { const { formatMessage, labels, messages } = useMessages(); const { user } = useUser(); const { get } = useApi(); - const { getProps, refetch } = useFilterQuery( + const queryResult = useFilterQuery( ['team:websites', teamId], params => { return get(`/teams/${teamId}/websites`, { @@ -21,8 +21,8 @@ export function TeamWebsites({ teamId }) { { enabled: !!user }, ); - const handleWebsiteAdd = () => { - refetch(); + const handleChange = () => { + queryResult.refetch(); }; return ( @@ -36,13 +36,13 @@ export function TeamWebsites({ teamId }) { {formatMessage(labels.addWebsite)} - {close => ( - - )} + {close => } - {({ data }) => } + + {({ data }) => } + ); } diff --git a/src/app/(main)/settings/teams/[id]/TeamWebsitesTable.js b/src/app/(main)/settings/teams/[id]/TeamWebsitesTable.js index 8a6c6ebe..0f802212 100644 --- a/src/app/(main)/settings/teams/[id]/TeamWebsitesTable.js +++ b/src/app/(main)/settings/teams/[id]/TeamWebsitesTable.js @@ -1,10 +1,10 @@ -import useMessages from 'components/hooks/useMessages'; -import useUser from 'components/hooks/useUser'; import Link from 'next/link'; import { Button, GridColumn, GridTable, Icon, Icons, Text } from 'react-basics'; -import TeamWebsiteRemoveButton from '../TeamWebsiteRemoveButton'; +import useMessages from 'components/hooks/useMessages'; +import useUser from 'components/hooks/useUser'; +import TeamWebsiteRemoveButton from './TeamWebsiteRemoveButton'; -export function TeamWebsitesTable({ data = [], onSave }) { +export function TeamWebsitesTable({ data = [], onRemove }) { const { formatMessage, labels } = useMessages(); const { user } = useUser(); @@ -20,6 +20,9 @@ export function TeamWebsitesTable({ data = [], onSave }) { const canRemove = user.id === userId || user.id === owner.userId; return ( <> + {canRemove && ( + + )} - {canRemove && ( - - )} ); }} diff --git a/src/app/(main)/settings/teams/page.js b/src/app/(main)/settings/teams/page.js index d2d0ff16..6af7eab2 100644 --- a/src/app/(main)/settings/teams/page.js +++ b/src/app/(main)/settings/teams/page.js @@ -1,4 +1,4 @@ -import TeamsList from 'app/(main)/settings/teams/TeamsList'; +import TeamsDataTable from './TeamsDataTable'; import TeamsHeader from './TeamsHeader'; export default function () { @@ -9,7 +9,7 @@ export default function () { return ( <> - + ); } diff --git a/src/app/(main)/settings/users/UsersList.js b/src/app/(main)/settings/users/UsersDataTable.js similarity index 62% rename from src/app/(main)/settings/users/UsersList.js rename to src/app/(main)/settings/users/UsersDataTable.js index 0bb90896..478aa3f3 100644 --- a/src/app/(main)/settings/users/UsersList.js +++ b/src/app/(main)/settings/users/UsersDataTable.js @@ -5,21 +5,20 @@ import DataTable from 'components/common/DataTable'; import UsersTable from './UsersTable'; import UsersHeader from './UsersHeader'; -export function UsersList() { +export function UsersDataTable() { const { get } = useApi(); - const filterQuery = useFilterQuery(['users'], params => { + const queryResult = useFilterQuery(['users'], params => { return get(`/users`, { ...params, }); }); - const { getProps } = filterQuery; return ( <> - {({ data }) => } + {({ data }) => } ); } -export default UsersList; +export default UsersDataTable; diff --git a/src/app/(main)/settings/users/page.tsx b/src/app/(main)/settings/users/page.tsx index b0af9fbb..bc0032d5 100644 --- a/src/app/(main)/settings/users/page.tsx +++ b/src/app/(main)/settings/users/page.tsx @@ -1,4 +1,4 @@ -import UsersList from 'app/(main)/settings/users/UsersList'; +import UsersDataTable from './UsersDataTable'; import { Metadata } from 'next'; export default function () { @@ -6,7 +6,7 @@ export default function () { return null; } - return ; + return ; } export const metadata: Metadata = { title: 'Users | umami', diff --git a/src/app/(main)/settings/websites/Websites.js b/src/app/(main)/settings/websites/WebsitesDataTable.js similarity index 59% rename from src/app/(main)/settings/websites/Websites.js rename to src/app/(main)/settings/websites/WebsitesDataTable.js index 693d6780..8bfb0190 100644 --- a/src/app/(main)/settings/websites/Websites.js +++ b/src/app/(main)/settings/websites/WebsitesDataTable.js @@ -6,16 +6,10 @@ import DataTable from 'components/common/DataTable'; import useFilterQuery from 'components/hooks/useFilterQuery'; import WebsitesHeader from './WebsitesHeader'; -export function Websites({ - showHeader = true, - showEditButton = true, - showTeam, - includeTeams, - onlyTeams, -}) { +function useWebsites({ includeTeams, onlyTeams }) { const { user } = useUser(); const { get } = useApi(); - const filterQuery = useFilterQuery( + return useFilterQuery( ['websites', { includeTeams, onlyTeams }], params => { return get(`/users/${user?.id}/websites`, { @@ -26,18 +20,38 @@ export function Websites({ }, { enabled: !!user }, ); - const { getProps } = filterQuery; +} + +export function WebsitesDataTable({ + showHeader = true, + showEditButton = true, + showViewButton = true, + showActions = true, + showTeam, + includeTeams, + onlyTeams, + children, +}) { + const queryResult = useWebsites({ includeTeams, onlyTeams }); return ( <> {showHeader && } - + {({ data }) => ( - + + {children} + )} ); } -export default Websites; +export default WebsitesDataTable; diff --git a/src/app/(main)/settings/websites/WebsitesTable.js b/src/app/(main)/settings/websites/WebsitesTable.js index 6ac977ab..15bd8882 100644 --- a/src/app/(main)/settings/websites/WebsitesTable.js +++ b/src/app/(main)/settings/websites/WebsitesTable.js @@ -3,7 +3,14 @@ import { Button, Text, Icon, Icons, GridTable, GridColumn } from 'react-basics'; import useMessages from 'components/hooks/useMessages'; import useUser from 'components/hooks/useUser'; -export function WebsitesTable({ data = [], showTeam, showEditButton }) { +export function WebsitesTable({ + data = [], + showTeam, + showActions, + showEditButton, + showViewButton, + children, +}) { const { formatMessage, labels } = useMessages(); const { user } = useUser(); @@ -30,7 +37,7 @@ export function WebsitesTable({ data = [], showTeam, showEditButton }) { return ( <> - {showEditButton && (!showTeam || ownerId === user.id) && ( + {showActions && showEditButton && (!showTeam || ownerId === user.id) && ( )} - - - + {showActions && showViewButton && ( + + + + )} ); }} + {children} ); } diff --git a/src/app/(main)/settings/websites/page.js b/src/app/(main)/settings/websites/page.js index 3cd5afa7..26d294a1 100644 --- a/src/app/(main)/settings/websites/page.js +++ b/src/app/(main)/settings/websites/page.js @@ -1,9 +1,9 @@ -import Websites from './Websites'; +import WebsitesDataTable from './WebsitesDataTable'; export default function () { if (process.env.cloudMode) { return null; } - return ; + return ; } diff --git a/src/app/(main)/websites/WebsitesBrowse.js b/src/app/(main)/websites/WebsitesBrowse.js index 8f2c5d51..1fa44a6d 100644 --- a/src/app/(main)/websites/WebsitesBrowse.js +++ b/src/app/(main)/websites/WebsitesBrowse.js @@ -1,5 +1,5 @@ 'use client'; -import WebsiteList from '../../(main)/settings/websites/Websites'; +import WebsiteList from '../settings/websites/WebsitesDataTable'; import { useMessages } from 'components/hooks'; import { useState } from 'react'; import { Item, Tabs } from 'react-basics'; diff --git a/src/components/common/DataTable.tsx b/src/components/common/DataTable.tsx index 489df475..df1468fb 100644 --- a/src/components/common/DataTable.tsx +++ b/src/components/common/DataTable.tsx @@ -9,19 +9,21 @@ import styles from './DataTable.module.css'; const DEFAULT_SEARCH_DELAY = 600; export interface DataTableProps { - result: { - page: number; - pageSize: number; - count: number; - data: any[]; + queryResult: { + result: { + page: number; + pageSize: number; + count: number; + data: any[]; + }; + params: { + query: string; + page: number; + }; + setParams: Dispatch>; + isLoading: boolean; + error: unknown; }; - params: { - query: string; - page: number; - }; - setParams: Dispatch>; - isLoading: boolean; - error: unknown; searchDelay?: number; showSearch?: boolean; showPaging?: boolean; @@ -29,20 +31,17 @@ export interface DataTableProps { } export function DataTable({ - result, - params, - setParams, - isLoading, - error, - searchDelay, + queryResult, + searchDelay = 600, showSearch = true, showPaging = true, children, }: DataTableProps) { const { formatMessage, labels, messages } = useMessages(); - const { pageSize, count } = result || {}; - const { query, page } = params || {}; - const hasData = Boolean(!isLoading && result?.data?.length); + const { result, error, isLoading, params, setParams } = queryResult || {}; + const { page, pageSize, count, data } = result || {}; + const { query } = params || {}; + const hasData = Boolean(!isLoading && data?.length); const noResults = Boolean(!isLoading && query && !hasData); const handleSearch = query => { diff --git a/src/components/hooks/useFilterQuery.ts b/src/components/hooks/useFilterQuery.ts index 987d3c44..1879180d 100644 --- a/src/components/hooks/useFilterQuery.ts +++ b/src/components/hooks/useFilterQuery.ts @@ -1,4 +1,4 @@ -import { useCallback, useState } from 'react'; +import { useState } from 'react'; import { useApi } from 'components/hooks/useApi'; export function useFilterQuery(key: any[], fn, options?: any) { @@ -8,19 +8,19 @@ export function useFilterQuery(key: any[], fn, options?: any) { }); const { useQuery } = useApi(); - const result = useQuery<{ - page: number; - pageSize: number; - count: number; - data: any[]; - }>([...key, params], fn.bind(null, params), options); + const { data, ...other } = useQuery([...key, params], fn.bind(null, params), options); - const getProps = useCallback(() => { - const { data, isLoading, error } = result; - return { result: data, isLoading, error, params, setParams }; - }, [result, params, setParams]); - - return { ...result, getProps }; + return { + result: data as { + page: number; + pageSize: number; + count: number; + data: any[]; + }, + ...other, + params, + setParams, + }; } export default useFilterQuery; diff --git a/src/index.ts b/src/index.ts index b56051e9..0aa8832f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -32,9 +32,9 @@ export * from 'app/(main)/settings/teams/[id]/TeamMemberRemoveButton'; export * from 'app/(main)/settings/teams/[id]/TeamMembers'; export * from 'app/(main)/settings/teams/[id]/TeamMembersTable'; export * from 'app/(main)/settings/teams/[id]/TeamSettings'; -export * from 'app/(main)/settings/teams/TeamsList'; +export * from 'app/(main)/settings/teams/TeamsDataTable'; export * from 'app/(main)/settings/teams/TeamsTable'; -export * from 'app/(main)/settings/teams/TeamWebsiteRemoveButton'; +export * from 'app/(main)/settings/teams/[id]/TeamWebsiteRemoveButton'; export * from 'app/(main)/settings/teams/[id]/TeamWebsites'; export * from 'app/(main)/settings/teams/[id]/TeamWebsitesTable'; export * from 'app/(main)/settings/teams/WebsiteTags'; @@ -46,5 +46,5 @@ export * from 'app/(main)/settings/websites/[id]/WebsiteDeleteForm'; export * from 'app/(main)/settings/websites/[id]/WebsiteEditForm'; export * from 'app/(main)/settings/websites/[id]/WebsiteResetForm'; export * from 'app/(main)/settings/websites/WebsiteSettings'; -export * from 'app/(main)/settings/websites/Websites'; +export * from 'app/(main)/settings/websites/WebsitesDataTable'; export * from 'app/(main)/settings/websites/WebsitesTable'; diff --git a/src/lib/middleware.ts b/src/lib/middleware.ts index e1e2a38b..5a12eb6a 100644 --- a/src/lib/middleware.ts +++ b/src/lib/middleware.ts @@ -88,7 +88,7 @@ export const useValidate = async (schema, req, res) => { const rules = schema[req.method]; if (rules) { - rules.validateSync(req.method === 'GET' ? { ...req.query } : { ...req.body }); + rules.validateSync({ ...req.query, ...req.body }); } } catch (e: any) { return badRequest(res, e.message);