Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/add emails #79

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added emails/LostandFoundHeader.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
92 changes: 92 additions & 0 deletions emails/subscription.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { Category, Item } from '@prisma/client';
import {
Body,
Column,
Container,
Head,
Heading,
Hr,
Html,
Img,
Preview,
Row,
Section,
Tailwind,
Text
} from '@react-email/components';

type Props = {
previewText?: string;
category?: Category;
items?: Item[];
baseUrl?: string;
username?: string;
};
export default function Email({
previewText = '',
category,
items,
baseUrl,
username
}: Props) {
return (
<Html>
<Head />
<Preview>{previewText}</Preview>
<Tailwind>
<Body className="my-auto mx-auto bg-white px-2 font-sans">
<Container className="my-[40px] mx-auto max-w-[465px] rounded border border-solid border-[#eaeaea] p-[20px]">
<Section className="mt-[32px]">
<Img
src={`${baseUrl}/static/logo.png`}
width="40"
height="37"
alt="Vercel"
className="my-0 mx-auto"
/>
</Section>
<Heading className="my-[30px] mx-0 p-0 text-center text-[24px] font-normal text-black">
Subscription Update
</Heading>
<Text className="text-[14px] leading-[24px] text-black">
Hello {username},
</Text>
<Text className="text-[14px] leading-[24px] text-black">
Daily updates for the category{' '}
<span className="font-semibold">{category}</span> are ready.
</Text>

<Section>
{items?.map((item) => (
<Row key={item.id}>
<Column align="right">
<Text>
Item Name:{' '}
<span className="font-semibold">{item.name}</span>
</Text>
</Column>
<Column align="right">
<Text>
Description:{' '}
<span className="font-semibold">{item.itemLocation}</span>
</Text>
</Column>
<Column align="right">
<Text>
Location:{' '}
<span className="font-semibold">
{item.shortDescription}
</span>
</Text>
</Column>
</Row>
))}
</Section>

<Hr className="my-[26px] mx-0 w-full border border-solid border-[#eaeaea]" />
</Container>
</Body>
</Tailwind>
</Html>
);
}
Empty file added emails/textcomponent.tsx
Empty file.
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@
"postinstall": "prisma generate",
"lint": "next lint",
"start": "next start",
"format": "yarn prettier . --write --ignore-path ./.gitignore"
"format": "yarn prettier . --write --ignore-path ./.gitignore",
"email-dev": "email dev",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@clerk/nextjs": "^4.29.7",
"@headlessui/react": "^1.7.13",
"@headlessui/tailwindcss": "^0.1.3",
"@hookform/resolvers": "^2.9.11",
"@prisma/client": "^4.12.0",
"@react-email/components": "^0.0.25",
"@tailwindcss/typography": "^0.5.7",
"@tanstack/react-query": "^4.24.6",
"@trpc/client": "^10.11.0",
Expand All @@ -24,6 +27,7 @@
"@trpc/server": "^10.11.0",
"clsx": "^1.2.1",
"daisyui": "^2.39.1",
"mailgun.js": "^10.2.3",
"mongodb": "^4.11.0",
"next": "14",
"next-themes": "^0.2.1",
Expand All @@ -38,6 +42,7 @@
"react-toastify": "^9.0.8",
"sharp": "^0.31.1",
"superjson": "1.9.1",
"tsx": "^4.19.0",
"zod": "^3.21.4",
"zod-validation-error": "^0.2.1",
"zustand": "^4.3.3"
Expand All @@ -62,6 +67,7 @@
"prettier-plugin-organize-imports": "^3.2.2",
"prettier-plugin-tailwindcss": "^0.2.2",
"prisma": "^4.12.0",
"react-email": "^3.0.1",
"tailwindcss": "^3.2.0",
"typescript": "^4.8.4"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
-- CreateEnum
CREATE TYPE "Location" AS ENUM ('AN', 'BH', 'BK', 'CUC', 'CIC', 'CFA', 'DH', 'GHC', 'HOA', 'HBH', 'HH', 'HL', 'III', 'MM', 'MI', 'NSH', 'PH', 'POS', 'PCA', 'TEP', 'OTHER');

-- CreateEnum
CREATE TYPE "RetrieveLocation" AS ENUM ('CUC', 'GHC');

-- CreateEnum
CREATE TYPE "Category" AS ENUM ('BEVERAGE_CONTAINER', 'CHARGER', 'CLOTHING', 'EARBUDS_HEADPHONES_CASES', 'GLASSES_CASES', 'JEWELRY_WATCHES', 'KEYS', 'PHONES_LAPTOPS_TABLETS', 'STATIONARY', 'UMBRELLA', 'OTHER');

-- CreateEnum
CREATE TYPE "Color" AS ENUM ('BLACK', 'BLUE', 'BROWN', 'GREEN', 'GREY', 'MULTICOLOR', 'METALLIC', 'ORANGE', 'PURPLE', 'RED', 'WHITE', 'YELLOW', 'OTHER');

-- CreateEnum
CREATE TYPE "ItemInteraction" AS ENUM ('CREATE', 'APPROVE', 'UNAPPROVE', 'ARCHIVE', 'UNARCHIVE', 'EDIT', 'DELETE');

-- CreateEnum
CREATE TYPE "Status" AS ENUM ('PENDING', 'APPROVED', 'ARCHIVED');

-- CreateEnum
CREATE TYPE "Value" AS ENUM ('GENERAL', 'HIGH');

-- CreateEnum
CREATE TYPE "Permission" AS ENUM ('USER', 'MODERATOR', 'ADMIN');

-- CreateTable
CREATE TABLE "Item" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"foundDate" TIMESTAMP(3) NOT NULL,
"foundLocation" "Location" NOT NULL,
"foundDescription" TEXT NOT NULL,
"shortDescription" TEXT NOT NULL,
"categories" "Category"[],
"color" "Color" NOT NULL,
"value" "Value" NOT NULL,
"identifiable" BOOLEAN NOT NULL,
"retrieveLocation" "RetrieveLocation" NOT NULL,
"itemLocation" TEXT NOT NULL,
"longDescription" TEXT,
"status" "Status" NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT "Item_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "AuditLog" (
"id" TEXT NOT NULL,
"interaction" "ItemInteraction" NOT NULL,
"actorId" TEXT NOT NULL,
"itemId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT "AuditLog_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "Subscription" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"category" "Category" NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT "Subscription_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "User" (
"id" TEXT NOT NULL,
"externalId" TEXT NOT NULL,
"notifications" BOOLEAN NOT NULL DEFAULT true,
"permission" "Permission" NOT NULL DEFAULT 'USER',

CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "VerificationToken" (
"id" TEXT NOT NULL,
"identifier" TEXT NOT NULL,
"token" TEXT NOT NULL,
"expires" TIMESTAMP(3) NOT NULL,

CONSTRAINT "VerificationToken_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "Subscription_userId_category_key" ON "Subscription"("userId", "category");

-- CreateIndex
CREATE UNIQUE INDEX "User_externalId_key" ON "User"("externalId");

-- CreateIndex
CREATE UNIQUE INDEX "VerificationToken_token_key" ON "VerificationToken"("token");

-- CreateIndex
CREATE UNIQUE INDEX "VerificationToken_identifier_token_key" ON "VerificationToken"("identifier", "token");

-- AddForeignKey
ALTER TABLE "AuditLog" ADD CONSTRAINT "AuditLog_actorId_fkey" FOREIGN KEY ("actorId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "AuditLog" ADD CONSTRAINT "AuditLog_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "Item"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Subscription" ADD CONSTRAINT "Subscription_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
3 changes: 3 additions & 0 deletions prisma/migrations/migration_lock.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "postgresql"
15 changes: 7 additions & 8 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ enum Permission {
}

model Item {
id String @id @default(cuid())
id String @id @default(cuid())
name String
foundDate DateTime
foundLocation Location
Expand All @@ -112,13 +112,13 @@ model Item {
longDescription String?
auditLogs AuditLog[]
status Status
createdAt DateTime @default(now())
createdAt DateTime @default(now())
}

model AuditLog {
id String @id @default(cuid())
interaction ItemInteraction
actor Account @relation(fields: [actorId], references: [clerkId], onDelete: Cascade)
actor User @relation(fields: [actorId], references: [id], onDelete: Cascade)
actorId String
item Item @relation(fields: [itemId], references: [id], onDelete: Cascade)
itemId String
Expand All @@ -128,21 +128,20 @@ model AuditLog {
model Subscription {
id String @id @default(cuid())
userId String
user Account @relation(fields: [userId], references: [clerkId], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
category Category
createdAt DateTime @default(now())

@@unique([userId, category])
}

model Account {
clerkId String @id @unique
model User {
id String @id @default(cuid())
externalId String @unique
notifications Boolean @default(true)
permission Permission @default(USER)
auditLogs AuditLog[]
subscriptions Subscription[]

@@index([clerkId])
}

model VerificationToken {
Expand Down
6 changes: 3 additions & 3 deletions src/components/Dialogs/UserEditDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ function EditUserForm() {
useEffect(() => {
if (!selectedUser) return;
methods.reset({
permission: selectedUser.account.permission,
notifications: selectedUser.account.notifications
permission: selectedUser.user.permission,
notifications: selectedUser.user.notifications
});
}, [selectedUser]);
const { clearDialog } = useDialogStore();
Expand All @@ -40,7 +40,7 @@ function EditUserForm() {
<form
onSubmit={methods.handleSubmit((data) => {
userUpdateMutation.mutate({
clerkId: selectedUser.account.clerkId,
externalId: selectedUser.user.externalId,
data
});
}, console.error)}
Expand Down
4 changes: 1 addition & 3 deletions src/components/ItemHistory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ export function ItemHistory({ item }: ItemHistoryProps) {
Modified By
</div>
<div className="collapse-content whitespace-normal text-xs">
<p>
{auditLogQuery.data.map((audit) => audit.actor.clerkId).join('\n')}
</p>
<p>{auditLogQuery.data.map((audit) => audit.actor.id).join('\n')}</p>
</div>
</button>
<button type="button" tabIndex={0} className="collapse-arrow collapse">
Expand Down
14 changes: 6 additions & 8 deletions src/components/UserRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default function UserRow({
<div className="avatar">
<div className="w-8 rounded-full sm:w-12">
<Image
src={data.user.imageUrl ?? '/pfp.png'}
src={data.clerkUser.imageUrl ?? '/pfp.png'}
width={48}
height={48}
alt="img"
Expand All @@ -34,20 +34,18 @@ export default function UserRow({
<div className="flex-1">
<div className="w-24">
<div className="overflow-hidden text-ellipsis font-bold leading-5 sm:overflow-visible sm:text-lg">
{data.user.firstName} {data.user.lastName}
{data.clerkUser.firstName} {data.clerkUser.lastName}
</div>
<div className="overflow-hidden text-ellipsis text-sm text-base-content/50 sm:overflow-visible">
{data.user.emailAddresses[0]?.emailAddress ?? 'No Email'}
{data.clerkUser.emailAddresses[0]?.emailAddress ?? 'No Email'}
</div>
</div>
</div>
<div className="text-xs font-bold opacity-70">
{data.account.permission}
</div>
<div className="text-xs font-bold opacity-70">{data.user.permission}</div>
<div
className="tooltip"
data-tip={
data.account.notifications
data.user.notifications
? 'Notifications Enabled'
: 'Notifications Disabled'
}
Expand All @@ -57,7 +55,7 @@ export default function UserRow({
<input
type="checkbox"
className="cursor-none"
checked={data.account.notifications}
checked={data.user.notifications}
readOnly
/>
<div className="swap-on">
Expand Down
9 changes: 9 additions & 0 deletions src/lib/mailgun.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import FormData from 'form-data';
import Mailgun from 'mailgun.js';

const mailgun = new Mailgun(FormData);

export const mg = mailgun.client({
username: 'api',
key: process.env.MAILGUN_API_KEY || 'key-yourkeyhere'
});
4 changes: 2 additions & 2 deletions src/lib/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ export const ItemSearchSchema = z.object({
});

export const UserSchema = z.object({
clerkId: z.string(),
externalId: z.string(),
permission: z.nativeEnum(Permission),
notifications: z.boolean()
});
export const UserCreateSchema = UserSchema;
export const UserUpdateSchema = z.object({
clerkId: z.string(),
externalId: z.string(),
data: UserSchema.partial()
});
export const UserListSchema = z.object({
Expand Down
Loading
Loading