diff --git a/src/actions/card.ts b/src/actions/card.ts index 321ea50..9396a05 100644 --- a/src/actions/card.ts +++ b/src/actions/card.ts @@ -3,15 +3,16 @@ import { requireUser } from '@/actions/auth'; import { db } from '@/db'; import { UserPermissions } from '@/types/permissions'; -import { requirePermission } from '@/helpers/permissions'; +import { hasPermission, requirePermission } from '@/helpers/permissions'; import { addCardToUser } from '@/data/card'; import { AdminUser, getUsers } from '@/data/user'; import { ActionResult } from '@/types/action-result'; import { revalidatePath } from 'next/cache'; +import { getGlobalConfig } from '@/config'; +import { UserPayload } from '@/types/user'; +import { DB } from '@/types/db'; -export const getCards = async () => { - const user = await requireUser(); - +export const getCards = async (user: UserPayload) => { return db.selectFrom('aime_card') .where('user', '=', user.id) .selectAll() @@ -63,3 +64,36 @@ export const adminAddCardToUser = async (user: number, code: string): Promise> => { + const user = await requireUser(); + + if (!hasPermission(user.permissions, UserPermissions.USERMOD)) { + const cards = await getCards(user); + + if (!getGlobalConfig('allow_user_add_card')) + return { error: true, message: 'You do not have permissions to add a card' }; + + if (cards.length >= (getGlobalConfig('user_max_card') ?? Infinity)) + return { error: true, message: 'You cannot add a card because you have reached your max card count' }; + } + + const res = await addCardToUser(user.id, code); + + if (res.error) + return res; + + revalidatePath('/settings', 'page'); + revalidatePath('/admin/users', 'page'); + + return { + card: { + id: res.id, + access_code: code, + user: user.id, + created_date: new Date(), + is_locked: 0, + is_banned: 0, + last_login_date: null + }}; +}; diff --git a/src/app/(with-header)/admin/users/admin-user-list.tsx b/src/app/(with-header)/admin/users/admin-user-list.tsx index 92ce091..cf9afc4 100644 --- a/src/app/(with-header)/admin/users/admin-user-list.tsx +++ b/src/app/(with-header)/admin/users/admin-user-list.tsx @@ -7,8 +7,6 @@ import { USER_PERMISSION_NAMES, UserPermissions } from '@/types/permissions'; import { Button, Divider, Tooltip, Input, Accordion, AccordionItem, Spacer } from '@nextui-org/react'; import { ChevronDownIcon, CreditCardIcon, PencilSquareIcon, PlusIcon } from '@heroicons/react/24/outline'; import { usePromptModal } from '@/components/prompt-modal'; -import { ArrowPathIcon } from '@heroicons/react/24/outline'; -import { generateAccessCode } from '@/helpers/access-code'; import { useUser } from '@/helpers/use-user'; import { hasPermission } from '@/helpers/permissions'; import { AimeCard } from '@/components/aime-card'; @@ -19,6 +17,7 @@ import { TrashIcon } from '@heroicons/react/24/outline'; import { useConfirmModal } from '@/components/confirm-modal'; import Link from 'next/link'; import { PermissionIcon } from '@/components/permission-icon'; +import { promptAccessCode } from '@/components/prompt-access-code'; const FORMAT = { month: 'numeric', @@ -42,33 +41,13 @@ export const AdminUserList = ({ users: initialUsers }: { users: AdminUser[]; }) setOpenUsers(new Set([window.location.hash.slice(1)])); }, []); - const promptAccessCode = (message: string, onConfirm: (val: string) => void) => { - prompt({ - size: '2xl', - title: 'Enter Access Code', content: (val, setVal) => <> - { message } -
- setVal(v.replace(/\D/g, ''))} /> - - - -
- - }, v => onConfirm(v.replace(/\D/g, ''))); - } - return (
Users + } +
+ +
+ {cards.map(c => )} +
+ ); +}; diff --git a/src/app/(with-header)/settings/page.tsx b/src/app/(with-header)/settings/page.tsx index 2f49d92..291d93e 100644 --- a/src/app/(with-header)/settings/page.tsx +++ b/src/app/(with-header)/settings/page.tsx @@ -1,26 +1,24 @@ import { getCards } from '@/actions/card'; import { Divider } from '@nextui-org/react'; -import { AimeCard } from '@/components/aime-card'; import { UserSettings } from './user-settings'; +import { Cards } from './cards'; +import { requireUser } from '@/actions/auth'; +import { getGlobalConfig } from '@/config'; export default async function SettingsPage() { - const card = await getCards(); - + const user = await requireUser(); + const cards = await getCards(user); return (
-
-
+
+
-
-
Cards
- -
- {card.map(c => )} -
+
+
); diff --git a/src/components/prompt-access-code.tsx b/src/components/prompt-access-code.tsx new file mode 100644 index 0000000..69ce05d --- /dev/null +++ b/src/components/prompt-access-code.tsx @@ -0,0 +1,24 @@ +import { generateAccessCode } from '@/helpers/access-code'; +import { PromptCallback } from './prompt-modal'; +import { Button, Input, Tooltip } from '@nextui-org/react'; +import { ArrowPathIcon } from '@heroicons/react/24/outline'; + +export const promptAccessCode = (prompt: PromptCallback, message: string, onConfirm: (val: string) => void) => { + prompt({ + size: '2xl', + title: 'Enter Access Code', content: (val, setVal) => <> + {message} +
+ setVal(v.replace(/\D/g, ''))} /> + + + +
+ + }, v => onConfirm(v.replace(/\D/g, ''))); +}; diff --git a/src/components/prompt-modal.tsx b/src/components/prompt-modal.tsx index ffac581..2799958 100644 --- a/src/components/prompt-modal.tsx +++ b/src/components/prompt-modal.tsx @@ -6,7 +6,7 @@ import { useHashNavigation } from '@/helpers/use-hash-navigation'; type PromptOptions = { title: string, size?: ModalProps['size'] } & (({ message: string, content?: never } & Partial>) | { content: (value: string, setValue: (v: string) => void) => ReactNode, message?: never }); -type PromptCallback = (options: PromptOptions, onConfirm: (val: string) => void, onCancel?: () => void) => void; +export type PromptCallback = (options: PromptOptions, onConfirm: (val: string) => void, onCancel?: () => void) => void; const PromptContext = createContext(() => {}); export const PromptProvider = ({ children }: { children: ReactNode }) => {