diff --git a/src/app/(app)/dashboard/DashboardEdit.js b/src/app/(app)/dashboard/DashboardEdit.js
index f628599f..3af33867 100644
--- a/src/app/(app)/dashboard/DashboardEdit.js
+++ b/src/app/(app)/dashboard/DashboardEdit.js
@@ -1,3 +1,4 @@
+'use client';
import { useState, useMemo } from 'react';
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
import classNames from 'classnames';
@@ -7,7 +8,6 @@ import useDashboard, { saveDashboard } from 'store/dashboard';
import useMessages from 'components/hooks/useMessages';
import useApi from 'components/hooks/useApi';
import styles from './DashboardEdit.module.css';
-import Page from 'components/layout/Page';
const dragId = 'dashboard-website-ordering';
@@ -17,11 +17,7 @@ export function DashboardEdit() {
const { formatMessage, labels } = useMessages();
const [order, setOrder] = useState(websiteOrder || []);
const { get, useQuery } = useApi();
- const {
- data: result,
- isLoading,
- error,
- } = useQuery(['websites'], () => get('/websites', { includeTeams: 1 }));
+ const { data: result } = useQuery(['websites'], () => get('/websites', { includeTeams: 1 }));
const { data: websites } = result || {};
const ordered = useMemo(() => {
@@ -59,7 +55,7 @@ export function DashboardEdit() {
}
return (
-
+ <>
-
+ >
);
}
diff --git a/src/app/(app)/layout.tsx b/src/app/(app)/layout.tsx
index c579f2c4..1c9cc277 100644
--- a/src/app/(app)/layout.tsx
+++ b/src/app/(app)/layout.tsx
@@ -1,4 +1,3 @@
-'use client';
import Shell from './Shell';
import NavBar from './NavBar';
import Page from 'components/layout/Page';
diff --git a/src/app/(app)/reports/ReportsTable.js b/src/app/(app)/reports/ReportsTable.js
index 72b0c273..4c81faa7 100644
--- a/src/app/(app)/reports/ReportsTable.js
+++ b/src/app/(app)/reports/ReportsTable.js
@@ -4,7 +4,6 @@ import { useMessages } from 'components/hooks';
import useUser from 'components/hooks/useUser';
import {
Button,
- Flexbox,
GridColumn,
GridTable,
Icon,
@@ -43,7 +42,7 @@ export function ReportsTable({ data = [], onDelete, showDomain }) {
{row => {
const { id, name, userId, website } = row;
return (
-
+ <>
{formatMessage(labels.view)}
{(user.id === userId || user.id === website?.userId) && (
@@ -64,7 +63,7 @@ export function ReportsTable({ data = [], onDelete, showDomain }) {
)}
-
+ >
);
}}
diff --git a/src/app/(app)/settings/layout.module.css b/src/app/(app)/settings/layout.module.css
index ef31160d..b87f75d0 100644
--- a/src/app/(app)/settings/layout.module.css
+++ b/src/app/(app)/settings/layout.module.css
@@ -11,6 +11,8 @@
}
.content {
+ display: flex;
+ flex-direction: column;
min-height: 50vh;
}
diff --git a/src/app/(app)/settings/teams/TeamsTable.js b/src/app/(app)/settings/teams/TeamsTable.js
index 2254e5f7..ca5a7fa7 100644
--- a/src/app/(app)/settings/teams/TeamsTable.js
+++ b/src/app/(app)/settings/teams/TeamsTable.js
@@ -3,7 +3,7 @@ import useMessages from 'components/hooks/useMessages';
import useUser from 'components/hooks/useUser';
import { ROLES } from 'lib/constants';
import Link from 'next/link';
-import { Button, Flexbox, GridColumn, GridTable, Icon, Icons, Text } from 'react-basics';
+import { Button, GridColumn, GridTable, Icon, Icons, Text } from 'react-basics';
import TeamDeleteButton from './TeamDeleteButton';
import TeamLeaveButton from './TeamLeaveButton';
@@ -24,7 +24,7 @@ export function TeamsTable({ data = [] }) {
const showDelete = user.id === owner?.userId;
return (
-
+ <>
+ >
);
}}
diff --git a/src/app/(app)/settings/teams/[id]/TeamMembers.js b/src/app/(app)/settings/teams/[id]/TeamMembers.js
index 6e29f0cf..f061d22d 100644
--- a/src/app/(app)/settings/teams/[id]/TeamMembers.js
+++ b/src/app/(app)/settings/teams/[id]/TeamMembers.js
@@ -1,46 +1,25 @@
-import { Loading, useToasts } from 'react-basics';
import useApi from 'components/hooks/useApi';
-import useMessages from 'components/hooks/useMessages';
-import useApiFilter from 'components/hooks/useApiFilter';
import TeamMembersTable from './TeamMembersTable';
+import useFilterQuery from 'components/hooks/useFilterQuery';
+import DataTable from 'components/common/DataTable';
export function TeamMembers({ teamId, readOnly }) {
- const { showToast } = useToasts();
- const { formatMessage, messages } = useMessages();
- const { filter, page, pageSize, handleFilterChange, handlePageChange, handlePageSizeChange } =
- useApiFilter();
- const { get, useQuery } = useApi();
- const { data, isLoading, refetch } = useQuery(
- ['teams:users', teamId, filter, page, pageSize],
- () =>
- get(`/teams/${teamId}/users`, {
- filter,
- page,
- pageSize,
- }),
+ const { get } = useApi();
+ const { getProps } = useFilterQuery(
+ ['team:users', teamId],
+ params => {
+ return get(`/teams/${teamId}/users`, {
+ ...params,
+ });
+ },
+ { enabled: !!teamId },
);
- if (isLoading) {
- return ;
- }
-
- const handleSave = async () => {
- await refetch();
- showToast({ message: formatMessage(messages.saved), variant: 'success' });
- };
-
return (
<>
-
+
+ {({ data }) => }
+
>
);
}
diff --git a/src/app/(app)/settings/teams/[id]/TeamMembersTable.js b/src/app/(app)/settings/teams/[id]/TeamMembersTable.js
index 0755c193..0c52280e 100644
--- a/src/app/(app)/settings/teams/[id]/TeamMembersTable.js
+++ b/src/app/(app)/settings/teams/[id]/TeamMembersTable.js
@@ -1,67 +1,36 @@
+import { GridColumn, GridTable } from 'react-basics';
import useMessages from 'components/hooks/useMessages';
import useUser from 'components/hooks/useUser';
import { ROLES } from 'lib/constants';
import TeamMemberRemoveButton from './TeamMemberRemoveButton';
-import SettingsTable from 'components/common/SettingsTable';
-export function TeamMembersTable({
- data = [],
- teamId,
- onSave,
- readOnly,
- filterValue,
- onFilterChange,
- onPageChange,
- onPageSizeChange,
-}) {
+export function TeamMembersTable({ data = [], teamId, readOnly, onChange }) {
const { formatMessage, labels } = useMessages();
const { user } = useUser();
- const columns = [
- { name: 'username', label: formatMessage(labels.username) },
- { name: 'role', label: formatMessage(labels.role) },
- { name: 'action', label: ' ' },
- ];
-
- const cellRender = (row, data, key) => {
- if (key === 'username') {
- return row?.username;
- }
- if (key === 'role') {
- return formatMessage(
- labels[
- Object.keys(ROLES).find(key => ROLES[key] === row?.teamUser[0]?.role) || labels.unknown
- ],
- );
- }
- return data[key];
+ const roles = {
+ [ROLES.teamOwner]: formatMessage(labels.teamOwner),
+ [ROLES.teamMember]: formatMessage(labels.teamMember),
};
return (
-
- {row => {
- return (
- !readOnly && (
-
- )
- );
- }}
-
+
+
+
+ {row => roles[row?.teamUser?.[0]?.role]}
+
+
+ {row => {
+ return (
+ !readOnly &&
+ row?.teamUser?.[0]?.role !== ROLES.teamOwner &&
+ user?.id !== row?.id && (
+
+ )
+ );
+ }}
+
+
);
}
diff --git a/src/app/(app)/settings/teams/[id]/TeamSettings.js b/src/app/(app)/settings/teams/[id]/TeamSettings.js
index 7c38430d..8ec0ad85 100644
--- a/src/app/(app)/settings/teams/[id]/TeamSettings.js
+++ b/src/app/(app)/settings/teams/[id]/TeamSettings.js
@@ -1,6 +1,6 @@
'use client';
import { useEffect, useState } from 'react';
-import { Item, Loading, Tabs, useToasts } from 'react-basics';
+import { Item, Loading, Tabs, useToasts, Flexbox } from 'react-basics';
import PageHeader from 'components/layout/PageHeader';
import { ROLES } from 'lib/constants';
import useUser from 'components/hooks/useUser';
@@ -46,7 +46,7 @@ export function TeamSettings({ teamId }) {
}
return (
- <>
+
- {formatMessage(labels.details)}
@@ -58,7 +58,7 @@ export function TeamSettings({ teamId }) {
)}
{tab === 'members' && }
{tab === 'websites' && }
- >
+
);
}
diff --git a/src/app/(app)/settings/teams/[id]/TeamWebsites.js b/src/app/(app)/settings/teams/[id]/TeamWebsites.js
index f7d67860..5f13027e 100644
--- a/src/app/(app)/settings/teams/[id]/TeamWebsites.js
+++ b/src/app/(app)/settings/teams/[id]/TeamWebsites.js
@@ -1,75 +1,49 @@
-import {
- ActionForm,
- Button,
- Icon,
- Icons,
- Loading,
- Modal,
- ModalTrigger,
- Text,
- useToasts,
-} from 'react-basics';
+import { ActionForm, Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics';
import TeamWebsitesTable from './TeamWebsitesTable';
import TeamAddWebsiteForm from './TeamAddWebsiteForm';
import useApi from 'components/hooks/useApi';
import useMessages from 'components/hooks/useMessages';
-import useApiFilter from 'components/hooks/useApiFilter';
+import useUser from 'components/hooks/useUser';
+import useFilterQuery from 'components/hooks/useFilterQuery';
+import DataTable from 'components/common/DataTable';
export function TeamWebsites({ teamId }) {
- const { showToast } = useToasts();
const { formatMessage, labels, messages } = useMessages();
- const { filter, page, pageSize, handleFilterChange, handlePageChange, handlePageSizeChange } =
- useApiFilter();
- const { get, useQuery } = useApi();
- const { data, isLoading, refetch } = useQuery(
- ['teams:websites', teamId, filter, page, pageSize],
- () =>
- get(`/teams/${teamId}/websites`, {
- filter,
- page,
- pageSize,
- }),
+ const { user } = useUser();
+ const { get } = useApi();
+ const { getProps, refetch } = useFilterQuery(
+ ['team:websites', teamId],
+ params => {
+ return get(`/teams/${teamId}/websites`, {
+ ...params,
+ });
+ },
+ { enabled: !!user },
);
- const hasData = data && data.length !== 0;
- if (isLoading) {
- return ;
- }
-
- const handleSave = async () => {
- await refetch();
- showToast({ message: formatMessage(messages.saved), variant: 'success' });
+ const handleWebsiteAdd = () => {
+ refetch();
};
- const addButton = (
-
-
-
- {close => }
-
-
- );
-
return (
-
-
{addButton}
- {hasData && (
-
- )}
-
+ <>
+
+
+
+
+ {close => (
+
+ )}
+
+
+
+ {({ data }) => }
+ >
);
}
diff --git a/src/app/(app)/settings/teams/[id]/TeamWebsitesTable.js b/src/app/(app)/settings/teams/[id]/TeamWebsitesTable.js
index 47d3af41..8a6c6ebe 100644
--- a/src/app/(app)/settings/teams/[id]/TeamWebsitesTable.js
+++ b/src/app/(app)/settings/teams/[id]/TeamWebsitesTable.js
@@ -1,65 +1,41 @@
import useMessages from 'components/hooks/useMessages';
import useUser from 'components/hooks/useUser';
import Link from 'next/link';
-import { Button, Icon, Icons, Text } from 'react-basics';
+import { Button, GridColumn, GridTable, Icon, Icons, Text } from 'react-basics';
import TeamWebsiteRemoveButton from '../TeamWebsiteRemoveButton';
-import SettingsTable from 'components/common/SettingsTable';
-export function TeamWebsitesTable({
- data = [],
- onSave,
- filterValue,
- onFilterChange,
- onPageChange,
- onPageSizeChange,
- openExternal = false,
-}) {
+export function TeamWebsitesTable({ data = [], onSave }) {
const { formatMessage, labels } = useMessages();
-
const { user } = useUser();
- const columns = [
- { name: 'name', label: formatMessage(labels.name) },
- { name: 'domain', label: formatMessage(labels.domain) },
- { name: 'action', label: ' ' },
- ];
return (
-
- {row => {
- const { id: teamId, teamUser } = row.teamWebsite[0].team;
- const { id: websiteId, name, domain, userId } = row;
- const owner = teamUser[0];
- const canRemove = user.id === userId || user.id === owner.userId;
-
- row.name = name;
- row.domain = domain;
-
- return (
- <>
-
-
-
- {canRemove && (
-
- )}
- >
- );
- }}
-
+
+
+
+
+ {row => {
+ const { id: teamId, teamUser } = row.teamWebsite[0].team;
+ const { id: websiteId, userId } = row;
+ const owner = teamUser[0];
+ const canRemove = user.id === userId || user.id === owner.userId;
+ return (
+ <>
+
+
+
+ {canRemove && (
+
+ )}
+ >
+ );
+ }}
+
+
);
}
diff --git a/src/app/(app)/settings/users/UsersTable.js b/src/app/(app)/settings/users/UsersTable.js
index 16cf065a..6712e4a5 100644
--- a/src/app/(app)/settings/users/UsersTable.js
+++ b/src/app/(app)/settings/users/UsersTable.js
@@ -1,4 +1,4 @@
-import { Button, Text, Icon, Icons, GridTable, GridColumn, Flexbox } from 'react-basics';
+import { Button, Text, Icon, Icons, GridTable, GridColumn } from 'react-basics';
import { formatDistance } from 'date-fns';
import Link from 'next/link';
import { ROLES } from 'lib/constants';
@@ -36,7 +36,7 @@ export function UsersTable({ data = [] }) {
{row => {
const { id, username } = row;
return (
-
+ <>
-
+ >
);
}}
diff --git a/src/app/(app)/settings/websites/WebsitesList.js b/src/app/(app)/settings/websites/Websites.js
similarity index 94%
rename from src/app/(app)/settings/websites/WebsitesList.js
rename to src/app/(app)/settings/websites/Websites.js
index 45f839ec..56805062 100644
--- a/src/app/(app)/settings/websites/WebsitesList.js
+++ b/src/app/(app)/settings/websites/Websites.js
@@ -6,7 +6,7 @@ import DataTable from 'components/common/DataTable';
import useFilterQuery from 'components/hooks/useFilterQuery';
import WebsitesHeader from './WebsitesHeader';
-export function WebsitesList({
+export function Websites({
showHeader = true,
showEditButton = true,
showTeam,
@@ -40,4 +40,4 @@ export function WebsitesList({
);
}
-export default WebsitesList;
+export default Websites;
diff --git a/src/app/(app)/settings/websites/WebsitesList.module.css b/src/app/(app)/settings/websites/Websites.module.css
similarity index 100%
rename from src/app/(app)/settings/websites/WebsitesList.module.css
rename to src/app/(app)/settings/websites/Websites.module.css
diff --git a/src/app/(app)/settings/websites/WebsitesTable.js b/src/app/(app)/settings/websites/WebsitesTable.js
index 3739de64..6ac977ab 100644
--- a/src/app/(app)/settings/websites/WebsitesTable.js
+++ b/src/app/(app)/settings/websites/WebsitesTable.js
@@ -1,5 +1,5 @@
import Link from 'next/link';
-import { Button, Text, Icon, Icons, GridTable, GridColumn, Flexbox } from 'react-basics';
+import { Button, Text, Icon, Icons, GridTable, GridColumn } from 'react-basics';
import useMessages from 'components/hooks/useMessages';
import useUser from 'components/hooks/useUser';
@@ -29,7 +29,7 @@ export function WebsitesTable({ data = [], showTeam, showEditButton }) {
} = row;
return (
-
+ <>
{showEditButton && (!showTeam || ownerId === user.id) && (
-
+ >
);
}}
diff --git a/src/app/(app)/settings/websites/page.js b/src/app/(app)/settings/websites/page.js
index ade3e3ad..3cd5afa7 100644
--- a/src/app/(app)/settings/websites/page.js
+++ b/src/app/(app)/settings/websites/page.js
@@ -1,9 +1,9 @@
-import WebsitesList from 'app/(app)/settings/websites/WebsitesList';
+import Websites from './Websites';
export default function () {
if (process.env.cloudMode) {
return null;
}
- return ;
+ return ;
}
diff --git a/src/app/(app)/websites/WebsitesBrowse.js b/src/app/(app)/websites/WebsitesBrowse.js
index 006d0a40..96a25743 100644
--- a/src/app/(app)/websites/WebsitesBrowse.js
+++ b/src/app/(app)/websites/WebsitesBrowse.js
@@ -1,5 +1,5 @@
'use client';
-import WebsiteList from 'app/(app)/settings/websites/WebsitesList';
+import WebsiteList from '../settings/websites/Websites';
import { useMessages } from 'components/hooks';
import { useState } from 'react';
import { Item, Tabs } from 'react-basics';
diff --git a/src/components/common/DataTable.module.css b/src/components/common/DataTable.module.css
index b7426a7c..4ca52b74 100644
--- a/src/components/common/DataTable.module.css
+++ b/src/components/common/DataTable.module.css
@@ -23,6 +23,9 @@
}
.body td {
+ display: flex;
+ gap: 10px;
+ min-height: 70px;
align-items: center;
}
diff --git a/src/components/common/SettingsTable.js b/src/components/common/SettingsTable.js
deleted file mode 100644
index 701dbe13..00000000
--- a/src/components/common/SettingsTable.js
+++ /dev/null
@@ -1,100 +0,0 @@
-import Empty from 'components/common/Empty';
-import useMessages from 'components/hooks/useMessages';
-import { useState } from 'react';
-import {
- SearchField,
- Table,
- TableBody,
- TableCell,
- TableColumn,
- TableHeader,
- TableRow,
-} from 'react-basics';
-import styles from './SettingsTable.module.css';
-import Pager from 'components/common/Pager';
-
-export function SettingsTable({
- columns = [],
- data,
- children,
- cellRender,
- showSearch,
- showPaging,
- onFilterChange,
- onPageChange,
- onPageSizeChange,
- filterValue,
-}) {
- const { formatMessage, labels, messages } = useMessages();
- const [filter, setFilter] = useState(filterValue);
- const { data: value, page, count, pageSize } = data;
-
- const handleFilterChange = value => {
- setFilter(value);
- onFilterChange(value);
- };
-
- return (
- <>
- {showSearch && (value.length > 0 || filterValue) && (
-
- )}
- {value.length === 0 && filterValue && (
-
- )}
- {value.length > 0 && (
-
-
- {(column, index) => {
- return (
-
- {column.label}
-
- );
- }}
-
-
- {(row, keys, rowIndex) => {
- row.action = children(row, keys, rowIndex);
-
- return (
-
- {(data, key, colIndex) => {
- return (
-
-
- {cellRender ? cellRender(row, data, key, colIndex) : data[key]}
-
- );
- }}
-
- );
- }}
-
- {showPaging && (
-
- )}
-
- )}
- >
- );
-}
-
-export default SettingsTable;
diff --git a/src/components/common/SettingsTable.module.css b/src/components/common/SettingsTable.module.css
deleted file mode 100644
index fd6cddfa..00000000
--- a/src/components/common/SettingsTable.module.css
+++ /dev/null
@@ -1,44 +0,0 @@
-.cell {
- align-items: center;
-}
-
-.row .cell:last-child {
- gap: 10px;
- justify-content: flex-end;
-}
-
-.label {
- display: none;
- font-weight: 700;
-}
-
-@media screen and (max-width: 992px) {
- .header .cell {
- display: none;
- }
-
- .label {
- display: block;
- min-width: 100px;
- }
-
- .row .cell {
- padding-left: 0;
- flex-basis: 100%;
- }
-}
-
-@media screen and (max-width: 1200px) {
- .row {
- flex-wrap: wrap;
- }
-
- .header .cell:last-child {
- display: none;
- }
-
- .row .cell:last-child {
- padding-left: 0;
- flex-basis: 100%;
- }
-}
diff --git a/src/components/layout/Page.tsx b/src/components/layout/Page.tsx
index a96e5a4c..2f702012 100644
--- a/src/components/layout/Page.tsx
+++ b/src/components/layout/Page.tsx
@@ -1,3 +1,4 @@
+'use client';
import { ReactNode } from 'react';
import classNames from 'classnames';
import { Banner, Loading } from 'react-basics';
diff --git a/src/components/layout/PageHeader.tsx b/src/components/layout/PageHeader.tsx
index d1ea9bf9..c92a89a0 100644
--- a/src/components/layout/PageHeader.tsx
+++ b/src/components/layout/PageHeader.tsx
@@ -5,7 +5,7 @@ import styles from './PageHeader.module.css';
export interface PageHeaderProps {
title?: string;
className?: string;
- children: ReactNode;
+ children?: ReactNode;
}
export function PageHeader({ title, className, children }: PageHeaderProps) {
diff --git a/src/index.ts b/src/index.ts
index 72fe733b..aeaf318a 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -12,7 +12,6 @@ export * from 'components/common/HoverTooltip';
export * from 'components/common/LinkButton';
export * from 'components/common/MobileMenu';
export * from 'components/common/Pager';
-export * from 'components/common/SettingsTable';
export * from 'components/common/UpdateNotice';
export * from 'components/common/WorldMap';
@@ -113,5 +112,5 @@ export * from 'app/(app)/settings/websites/[id]/WebsiteDeleteForm';
export * from 'app/(app)/settings/websites/[id]/WebsiteEditForm';
export * from 'app/(app)/settings/websites/[id]/WebsiteResetForm';
export * from 'app/(app)/settings/websites/WebsiteSettings';
-export * from 'app/(app)/settings/websites/WebsitesList';
+export * from './app/(app)/settings/websites/Websites';
export * from 'app/(app)/settings/websites/WebsitesTable';
diff --git a/src/lib/prisma.ts b/src/lib/prisma.ts
index 442ee202..4b910f00 100644
--- a/src/lib/prisma.ts
+++ b/src/lib/prisma.ts
@@ -189,7 +189,7 @@ function getPageFilters(filters: SearchFilter): [
return [
{
- ...(pageSize > 0 && { take: pageSize, skip: pageSize * (page - 1) }),
+ ...(pageSize > 0 && { take: +pageSize, skip: +pageSize * (page - 1) }),
...(orderBy && {
orderBy: [
{
diff --git a/src/pages/api/users/[id]/websites.ts b/src/pages/api/users/[id]/websites.ts
index ede26738..26170472 100644
--- a/src/pages/api/users/[id]/websites.ts
+++ b/src/pages/api/users/[id]/websites.ts
@@ -30,7 +30,7 @@ export default async (
await useValidate(schema, req, res);
const { user } = req.auth;
- const { id: userId, page, query, includeTeams, onlyTeams } = req.query;
+ const { id: userId, page = 1, query = '', includeTeams, onlyTeams } = req.query;
if (req.method === 'GET') {
if (!user.isAdmin && user.id !== userId) {
@@ -38,8 +38,8 @@ export default async (
}
const websites = await getWebsitesByUserId(userId, {
- page: +page,
- query: query as string,
+ page,
+ query,
includeTeams,
onlyTeams,
});