Skip to content

Commit

Permalink
feat(dash/admin): ✨ Contacts page
Browse files Browse the repository at this point in the history
  • Loading branch information
Nudelsuppe42 committed Dec 17, 2024
1 parent 949b3de commit f043c96
Show file tree
Hide file tree
Showing 5 changed files with 269 additions and 0 deletions.
37 changes: 37 additions & 0 deletions apps/dashboard/src/app/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,40 @@ export const deleteUpload = async (id: string) => {

revalidatePath('/am/uploads/check');
};

export const addContact = async (data: { name: string; role: string; email: string; discord: string }) => {
const contact = await prisma.contact.create({
data,
});

revalidatePath('/am/contacts');
return contact;
};

export const editContact = async (data: { id: string; name: string; role: string; email: string; discord: string }) => {
const contact = await prisma.contact.update({
where: {
id: data.id,
},
data: {
name: data.name,
role: data.role,
email: data.email,
discord: data.discord,
},
});

revalidatePath('/am/contacts');
return contact;
};

export const deleteContact = async (id: any) => {
const contact = await prisma.contact.delete({
where: {
id,
},
});

revalidatePath('/am/contacts');
return contact;
};
52 changes: 52 additions & 0 deletions apps/dashboard/src/app/am/contacts/datatable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
'use client';

import { ActionIcon, Code, Group } from '@mantine/core';

import Anchor from '@/components/core/Anchor';
import { Contact } from '@repo/db';
import { IconExternalLink } from '@tabler/icons-react';
import { DataTable } from 'mantine-datatable';
import Link from 'next/link';
import { EditContactButton } from './interactivity';

export default function ContactsDatatable({ contacts }: { contacts: Contact[] }) {
return (
<DataTable
columns={[
{
accessor: 'id',
title: '#',
render: ({ id }) => <Code>{id.split('-')[0]}</Code>,
footer: contacts.length + ' Contacts',
},
{ accessor: 'name' },
{ accessor: 'role' },
{ accessor: 'email', render: ({ email }) => <Anchor href={`mailto:${email}`}>{email}</Anchor> },
{ accessor: 'discord' },
{
accessor: '',
title: '',
textAlign: 'right',
render: (contact: Contact) => (
<Group gap={4} justify="right" wrap="nowrap">
<EditContactButton {...contact} />
<ActionIcon
size="sm"
variant="subtle"
color="cyan"
aria-label="View Question on Website"
component={Link}
href={`https://buildtheearth.net/contact#:~:text=${encodeURIComponent(contact.name)}`}
target="_blank"
rel="noopener"
>
<IconExternalLink size={16} />
</ActionIcon>
</Group>
),
},
]}
records={contacts}
/>
);
}
127 changes: 127 additions & 0 deletions apps/dashboard/src/app/am/contacts/interactivity.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
'use client';

import { addContact, deleteContact, editContact } from '@/app/actions';
import { ActionIcon, Button, Group, TextInput } from '@mantine/core';
import { IconDeviceFloppy, IconEdit, IconPlus, IconTrash } from '@tabler/icons-react';

import { useFormActions } from '@/hooks/useFormAction';
import { useForm } from '@mantine/form';
import { modals } from '@mantine/modals';
import { Contact } from '@repo/db';

export function AddContactButton() {
return (
<Button
color="green"
leftSection={<IconPlus size={14} />}
onClick={() =>
modals.open({
id: 'add-contact',
title: 'Add new Contact',
centered: true,
size: 'lg',
children: <EditContactModal isAdd id="" name="" role="" discord="" email="" avatar="" />,
})
}
>
Add New
</Button>
);
}

export function EditContactButton(props: Contact) {
return (
<ActionIcon
size="sm"
variant="subtle"
color="yellow"
aria-label="Edit Contact"
onClick={() =>
modals.open({
id: 'edit-contact',
title: 'Edit Contact',
centered: true,
size: 'lg',
children: <EditContactModal {...props} />,
})
}
>
<IconEdit size={16} />
</ActionIcon>
);
}

function EditContactModal(
props: {
isAdd?: boolean;
} & Contact,
) {
const form = useForm({
initialValues: {
id: props.id,
name: props.name,
role: props.role,
email: props.email,
discord: props.discord,
avatar: '',
},
});
const [[addContactAction, editContactAction, deleteContactAction], isPending] = useFormActions([
addContact,
editContact,
deleteContact,
]);

const handleSubmit = (values: Contact) => {
if (props.isAdd) {
addContactAction(values);
} else {
editContactAction(values);
}
modals.closeAll();
};

return (
<form onSubmit={form.onSubmit(handleSubmit)}>
<TextInput mt="md" placeholder="..." label="Name" required {...form.getInputProps('name')} />
<TextInput mt="md" placeholder="..." label="Role" required {...form.getInputProps('role')} />
<TextInput
mt="md"
placeholder={(form.getValues().name || '...') + '@buildtheearth.net'}
label="E-Mail"
required
{...form.getInputProps('email')}
/>
<TextInput
mt="md"
placeholder={form.getValues().name || '...'}
label="Discord"
required
{...form.getInputProps('discord')}
/>
{!props.isAdd ? (
<Group mt="md">
<Button type="submit" leftSection={<IconDeviceFloppy size={14} />} loading={isPending}>
Save Changes
</Button>
<Button
variant="outline"
onClick={() => {
deleteContactAction(props.id);
modals.closeAll();
}}
leftSection={<IconTrash size={14} />}
color="red"
loading={isPending}
>
Delete Question
</Button>
</Group>
) : (
<Button type="submit" mt="md" leftSection={<IconPlus size={14} />} loading={isPending}>
Add Question
</Button>
)}
</form>
);
}
20 changes: 20 additions & 0 deletions apps/dashboard/src/app/am/contacts/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Box, Title } from '@mantine/core';

import { DataTable } from 'mantine-datatable';

export default async function Page() {
return (
<Box mx="md" maw="90vw">
<Title order={1} mt="xl" mb="md">
Contacts
</Title>
<DataTable
columns={[{ accessor: 'id', title: '#' }, { accessor: 'question' }, { accessor: '', title: 'Actions' }]}
records={[]}
minHeight={500}
width={'100%'}
noRecordsText="Loading Contacts..."
/>
</Box>
);
}
33 changes: 33 additions & 0 deletions apps/dashboard/src/app/am/contacts/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Box, Button, Group, Title } from '@mantine/core';

import prisma from '@/util/db';
import { IconExternalLink } from '@tabler/icons-react';
import Link from 'next/link';
import ContactsDatatable from './datatable';
import { AddContactButton } from './interactivity';

export default async function Page() {
const contacts = await prisma.contact.findMany();

return (
<Box mx="md" maw="90vw">
<Group justify="space-between" w="100%" mt="xl" mb="md">
<Title order={1}>Contacts</Title>
<Group gap="xs">
<AddContactButton />
<Button
variant="light"
color="cyan"
component={Link}
href={`https://buildtheearth.net/contact`}
target="_blank"
rightSection={<IconExternalLink size={14} />}
>
Open Page
</Button>
</Group>
</Group>
<ContactsDatatable contacts={contacts} />
</Box>
);
}

0 comments on commit f043c96

Please sign in to comment.