Skip to content

Commit

Permalink
Merge pull request #145 from moinulmoin/refactor-codebase
Browse files Browse the repository at this point in the history
Refactor codebase and ui
  • Loading branch information
moinulmoin authored Dec 16, 2023
2 parents a4dba4b + 5099763 commit fe796d6
Show file tree
Hide file tree
Showing 25 changed files with 342 additions and 425 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"zod": "^3.22.4"
},
"devDependencies": {
"@tailwindcss/line-clamp": "^0.4.4",
"@tailwindcss/typography": "^0.5.10",
"@types/node": "20.10.4",
"@types/react": "18.2.45",
Expand Down
11 changes: 11 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 6 additions & 11 deletions src/app/api/auth/login/github/callback/route.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { OAuthRequestError } from "@lucia-auth/oauth";
import { cookies, headers } from "next/headers";
import { auth, githubAuth } from "~/lib/auth";

import type { NextRequest } from "next/server";
import { sendMail } from "~/server/actions";
import { auth, githubAuth } from "~/lib/auth";
import { sendMail } from "~/lib/resend";

export const GET = async (request: NextRequest) => {
const storedState = cookies().get("github_oauth_state")?.value;
Expand All @@ -30,20 +29,16 @@ export const GET = async (request: NextRequest) => {
picture: githubUser.avatar_url,
},
});
return user;
};

const user = await getUser();

const existingUser = await getExistingUser();
if (!existingUser) {
sendMail({
toMail: user.email,
data: {
name: user.name,
},
});
}
return user;
};

const user = await getUser();

const session = await auth.createSession({
userId: user.userId,
Expand Down
9 changes: 5 additions & 4 deletions src/app/dashboard/billing/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { AlertTriangleIcon } from "lucide-react";
import { BillingForm } from "~/components/billing-form";
import { Alert, AlertDescription, AlertTitle } from "~/components/ui/alert";
import { getPageSession } from "~/lib/auth";
import { stripe } from "~/lib/stripe";
import { getUserSubscriptionPlan } from "~/lib/subscription";
import { getUser } from "~/server/user";
import { type CurrentUser } from "~/types";

export const revalidate = 0;
export const dynamic = "force-dynamic";

export default async function Billing() {
const user = (await getUser()) as CurrentUser;
const session = await getPageSession();

const subscriptionPlan = await getUserSubscriptionPlan(user.id);
const subscriptionPlan = await getUserSubscriptionPlan(
session?.user?.userId as string
);

// If user has a pro plan, check cancel status on Stripe.
let isCanceled = false;
Expand Down
30 changes: 16 additions & 14 deletions src/app/dashboard/projects/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,24 @@
import { type Project } from "@prisma/client";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { getPageSession } from "~/lib/auth";
import db from "~/lib/db";
import { getUserSubscriptionPlan } from "~/lib/subscription";
import { getUser } from "~/server/user";

interface Payload {
name: string;
domain: string;
}

export async function createProject(payload: Payload) {
const user = await getUser();
const session = await getPageSession();

await db.project.create({
data: {
...payload,
user: {
connect: {
id: user?.id,
id: session?.user?.userId,
},
},
},
Expand All @@ -30,27 +30,29 @@ export async function createProject(payload: Payload) {
}

export async function checkIfFreePlanLimitReached() {
const user = await getUser();
const subscriptionPlan = await getUserSubscriptionPlan(user?.id as string);
const session = await getPageSession();
const subscriptionPlan = await getUserSubscriptionPlan(
session?.user?.userId as string
);

// If user is on a free plan.
// Check if user has reached limit of 3 projects.
if (subscriptionPlan?.isPro) return false;

const count = await db.project.count({
where: {
userId: user?.id,
userId: session?.user?.userId,
},
});

return count >= 3;
}

export async function getProjects() {
const user = await getUser();
const session = await getPageSession();
const projects = await db.project.findMany({
where: {
userId: user?.id,
userId: session?.user?.userId,
},
orderBy: {
createdAt: "desc",
Expand All @@ -60,34 +62,34 @@ export async function getProjects() {
}

export async function getProjectById(id: string) {
const user = await getUser();
const session = await getPageSession();
const project = await db.project.findFirst({
where: {
id,
userId: user?.id,
userId: session?.user?.userId,
},
});
return project as Project;
}

export async function updateProjectById(id: string, payload: Payload) {
const user = await getUser();
const session = await getPageSession();
await db.project.update({
where: {
id,
userId: user?.id,
userId: session?.user?.userId,
},
data: payload,
});
revalidatePath(`/dashboard/projects`);
}

export async function deleteProjectById(id: string) {
const user = await getUser();
const session = await getPageSession();
await db.project.delete({
where: {
id,
userId: user?.id,
userId: session?.user?.userId,
},
});
revalidatePath(`/dashboard/projects`);
Expand Down
2 changes: 1 addition & 1 deletion src/app/dashboard/projects/create-project-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
} from "~/components/ui/form";
import { Input } from "~/components/ui/input";
import { toast } from "~/components/ui/use-toast";
import { FreePlanLimitError } from "~/server/utils";
import { FreePlanLimitError } from "~/lib/utils";
import { checkIfFreePlanLimitReached, createProject } from "./action";

export const projectSchema = z.object({
Expand Down
50 changes: 50 additions & 0 deletions src/app/dashboard/settings/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"use server";

import { revalidatePath } from "next/cache";
import db from "~/lib/db";
import { getImageKeyFromUrl, isOurCdnUrl } from "~/lib/utils";
import { utapi } from "~/server/uploadthing";
import { type payload } from "~/types";

export const updateUser = async (id: string, payload: payload) => {
await db.user.update({
where: { id },
data: { ...payload },
});

revalidatePath("/dashboard/settings");
};

export async function removeUserOldImageFromCDN(
id: string,
newImageUrl: string
) {
const user = await db.user.findFirst({
where: { id },
select: { picture: true },
});

const currentImageUrl = user?.picture;

if (!currentImageUrl) throw new Error("User Picture Missing");

try {
if (isOurCdnUrl(currentImageUrl)) {
const currentImageFileKey = getImageKeyFromUrl(currentImageUrl);

await utapi.deleteFiles(currentImageFileKey as string);
revalidatePath("/dashboard/settings");
}
} catch (e) {
if (e instanceof Error) {
const newImageFileKey = getImageKeyFromUrl(newImageUrl);
await utapi.deleteFiles(newImageFileKey as string);
console.error(e.message);
}
}
}

export async function removeNewImageFromCDN(image: string) {
const imageFileKey = getImageKeyFromUrl(image);
await utapi.deleteFiles(imageFileKey as string);
}
8 changes: 4 additions & 4 deletions src/app/dashboard/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { type User } from "lucia";
import { type Metadata } from "next";
import { getUser } from "~/server/user";
import { type CurrentUser } from "~/types";
import { getPageSession } from "~/lib/auth";
import SettingsForm from "./settings-form";

export const metadata: Metadata = {
title: "Settings",
};

export default async function Settings() {
const currentUser = (await getUser()) as CurrentUser;
return <SettingsForm currentUser={currentUser} />;
const session = await getPageSession();
return <SettingsForm currentUser={session?.user as User} />;
}
73 changes: 29 additions & 44 deletions src/app/dashboard/settings/settings-form.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
"use client";

import { zodResolver } from "@hookform/resolvers/zod";
import { type User } from "lucia";
import { Loader2 } from "lucide-react";
import dynamic from "next/dynamic";
import { useEffect, useRef, useState, useTransition } from "react";
import { useForm } from "react-hook-form";
import {
removeNewImageFromCDN,
removeUserOldImageFromCDN,
updateUser,
} from "~/app/dashboard/settings/actions";
import { Avatar, AvatarFallback, AvatarImage } from "~/components/ui/avatar";
import { Button } from "~/components/ui/button";
import {
Expand All @@ -18,12 +24,7 @@ import {
} from "~/components/ui/form";
import { Input } from "~/components/ui/input";
import { toast } from "~/components/ui/use-toast";
import {
saRemoveNewImageFromCDN,
saRemoveUserOldImageFromCDN,
saUpdateUserInDb,
} from "~/server/actions";
import { settingsSchema, type CurrentUser, type SettingsValues } from "~/types";
import { settingsSchema, type SettingsValues } from "~/types";

const ImageUploadModal = dynamic(
() => import("~/components/layout/image-upload-modal")
Expand All @@ -33,11 +34,7 @@ const CancelConfirmModal = dynamic(
() => import("~/components/layout/cancel-confirm-modal")
);

export default function SettingsForm({
currentUser,
}: {
currentUser: CurrentUser;
}) {
export default function SettingsForm({ currentUser }: { currentUser: User }) {
const oldImage = useRef("");
const [pending, startTransition] = useTransition();

Expand Down Expand Up @@ -65,43 +62,31 @@ export default function SettingsForm({
function onSubmit(data: SettingsValues) {
if (!formState.isDirty) return;

if (isImageChanged) {
startTransition(() =>
saRemoveUserOldImageFromCDN(currentUser.id, data.picture)
.then(() => saUpdateUserInDb(currentUser.id, data))
.then(() => {
toast({
title: "Updated successfully!",
});
})
.catch(() => {
toast({
title: "Something went wrong.",
variant: "destructive",
});
})
);
} else {
startTransition(() =>
saUpdateUserInDb(currentUser.id, data)
.then(() => {
toast({
title: "Updated successfully!",
});
})
.catch(() => {
toast({
title: "Something went wrong.",
variant: "destructive",
});
})
);
}
startTransition(() => {
const updatePromise = isImageChanged
? removeUserOldImageFromCDN(currentUser.userId, data.picture).then(() =>
updateUser(currentUser.userId, data)
)
: updateUser(currentUser.userId, data);

return updatePromise
.then(() => {
toast({
title: "Updated successfully!",
});
})
.catch(() => {
toast({
title: "Something went wrong.",
variant: "destructive",
});
});
});
}

function handleReset() {
if (isImageChanged) {
saRemoveNewImageFromCDN(form.getValues().picture)
removeNewImageFromCDN(form.getValues().picture)
.then(() => form.reset())
.catch((error) => console.error(error));
} else {
Expand Down
Loading

1 comment on commit fe796d6

@vercel
Copy link

@vercel vercel bot commented on fe796d6 Dec 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.