diff --git a/components/Modal/User/ChangePassword.tsx b/components/Modal/User/ChangePassword.tsx index 5ccfe08..c299a43 100644 --- a/components/Modal/User/ChangePassword.tsx +++ b/components/Modal/User/ChangePassword.tsx @@ -23,7 +23,7 @@ export default function ChangePassword({ const [submitLoader, setSubmitLoader] = useState(false); const { account, updateAccount } = useAccountStore(); - const { update } = useSession(); + const { update, data } = useSession(); useEffect(() => { if ( @@ -57,9 +57,7 @@ export default function ChangePassword({ user.name !== account.name ) { update({ - username: user.username, - email: user.email, - name: user.name, + id: data?.user.id, }); signOut(); diff --git a/components/Modal/User/PrivacySettings.tsx b/components/Modal/User/PrivacySettings.tsx index 79dbb5a..6047448 100644 --- a/components/Modal/User/PrivacySettings.tsx +++ b/components/Modal/User/PrivacySettings.tsx @@ -18,7 +18,7 @@ export default function PrivacySettings({ setUser, user, }: Props) { - const { update } = useSession(); + const { update, data } = useSession(); const { account, updateAccount } = useAccountStore(); const [submitLoader, setSubmitLoader] = useState(false); @@ -66,9 +66,7 @@ export default function PrivacySettings({ user.name !== account.name ) { update({ - username: user.username, - email: user.email, - name: user.name, + id: data?.user.id, }); signOut(); diff --git a/components/Modal/User/ProfileSettings.tsx b/components/Modal/User/ProfileSettings.tsx index cee20bd..76b5fe4 100644 --- a/components/Modal/User/ProfileSettings.tsx +++ b/components/Modal/User/ProfileSettings.tsx @@ -23,7 +23,7 @@ export default function ProfileSettings({ setUser, user, }: Props) { - const { update } = useSession(); + const { update, data } = useSession(); const { account, updateAccount } = useAccountStore(); const [profileStatus, setProfileStatus] = useState(true); @@ -84,9 +84,7 @@ export default function ProfileSettings({ user.name !== account.name ) { update({ - username: user.username, - email: user.email, - name: user.name, + id: data?.user.id, }); signOut(); @@ -158,7 +156,7 @@ export default function ProfileSettings({
Username
setUser({ ...user, username: e.target.value })} className="w-full rounded-md p-2 border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" /> diff --git a/layouts/AuthRedirect.tsx b/layouts/AuthRedirect.tsx index 35c2ceb..a5fd1ad 100644 --- a/layouts/AuthRedirect.tsx +++ b/layouts/AuthRedirect.tsx @@ -14,11 +14,26 @@ export default function AuthRedirect({ children }: Props) { const { status, data } = useSession(); const [redirect, setRedirect] = useState(true); + const emailEnabled = process.env.NEXT_PUBLIC_EMAIL_PROVIDER; + useInitialData(); useEffect(() => { if (!router.pathname.startsWith("/public")) { - if (status === "authenticated" && data.user.isSubscriber === false) { + if ( + emailEnabled && + status === "authenticated" && + (data.user.isSubscriber === true || + data.user.isSubscriber === undefined) && + !data.user.username + ) { + router.push("/choose-username").then(() => { + setRedirect(false); + }); + } else if ( + status === "authenticated" && + data.user.isSubscriber === false + ) { router.push("/subscribe").then(() => { setRedirect(false); }); @@ -28,6 +43,7 @@ export default function AuthRedirect({ children }: Props) { router.pathname === "/register" || router.pathname === "/confirmation" || router.pathname === "/subscribe" || + router.pathname === "/choose-username" || router.pathname === "/forgot") ) { router.push("/").then(() => { diff --git a/lib/api/paymentCheckout.ts b/lib/api/paymentCheckout.ts index 9c2893c..34f8e86 100644 --- a/lib/api/paymentCheckout.ts +++ b/lib/api/paymentCheckout.ts @@ -10,12 +10,6 @@ export default async function paymentCheckout( apiVersion: "2022-11-15", }); - // const a = await stripe.prices.retrieve("price_1NTn3PDaRUw6CJPLkw4dcwlJ"); - - // const listBySub = await stripe.subscriptions.list({ - // customer: "cus_OGUzJrRea8Qbxx", - // }); - const listByEmail = await stripe.customers.list({ email: email.toLowerCase(), expand: ["data.subscriptions"], @@ -23,31 +17,6 @@ export default async function paymentCheckout( const isExistingCostomer = listByEmail?.data[0]?.id || undefined; - // const hasPreviouslySubscribed = listByEmail.data.find((customer, i) => { - // const hasValidSubscription = customer.subscriptions?.data.some( - // (subscription) => { - // return subscription?.items?.data?.some( - // (subscriptionItem) => subscriptionItem?.plan?.id === priceId - // ); - // } - // ); - - // return ( - // customer.email?.toLowerCase() === email.toLowerCase() && - // hasValidSubscription - // ); - // }); - - // const previousSubscriptionId = - // hasPreviouslySubscribed?.subscriptions?.data[0].id; - - // if (previousSubscriptionId) { - // console.log(previousSubscriptionId); - // const subscription = await stripe.subscriptions.resume( - // previousSubscriptionId - // ); - // } - const TRIAL_PERIOD_DAYS = process.env.TRIAL_PERIOD_DAYS; const session = await stripe.checkout.sessions.create({ customer: isExistingCostomer ? isExistingCostomer : undefined, diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts index 6de9f51..e760f2e 100644 --- a/pages/api/auth/[...nextauth].ts +++ b/pages/api/auth/[...nextauth].ts @@ -126,11 +126,20 @@ export const authOptions: AuthOptions = { if (trigger === "signIn") { token.id = user.id; token.username = (user as any).username; - } else if (trigger === "update" && session?.name && session?.username) { - // Note, that `session` can be any arbitrary object, remember to validate it! - token.name = session.name; - token.username = session.username.toLowerCase(); - token.email = session.email.toLowerCase(); + } else if (trigger === "update" && token.id) { + console.log(token); + + const user = await prisma.user.findUnique({ + where: { + id: token.id as number, + }, + }); + + if (user) { + token.name = user.name; + token.username = user.username?.toLowerCase(); + token.email = user.email?.toLowerCase(); + } } return token; }, diff --git a/pages/api/auth/register.ts b/pages/api/auth/register.ts index 44406ee..4abf03e 100644 --- a/pages/api/auth/register.ts +++ b/pages/api/auth/register.ts @@ -11,7 +11,7 @@ interface Data { interface User { name: string; - username: string; + username?: string; email?: string; password: string; } @@ -23,7 +23,7 @@ export default async function Index( const body: User = req.body; const checkHasEmptyFields = emailEnabled - ? !body.username || !body.password || !body.name || !body.email + ? !body.password || !body.name || !body.email : !body.username || !body.password || !body.name; if (checkHasEmptyFields) @@ -31,30 +31,9 @@ export default async function Index( .status(400) .json({ response: "Please fill out all the fields." }); - const tenMinutesAgo = new Date(Date.now() - 10 * 60 * 1000); - - // Remove user's who aren't verified for more than 10 minutes - if (emailEnabled) - await prisma.user.deleteMany({ - where: { - OR: [ - { - email: body.email, - }, - { - username: body.username, - }, - ], - createdAt: { - lt: tenMinutesAgo, - }, - emailVerified: null, - }, - }); - const checkUsername = RegExp("^[a-z0-9_-]{3,31}$"); - if (!checkUsername.test(body.username)) + if (!emailEnabled && !checkUsername.test(body.username || "")) return res.status(400).json({ response: "Username has to be between 3-30 characters, no spaces and special characters are allowed.", @@ -63,18 +42,11 @@ export default async function Index( const checkIfUserExists = await prisma.user.findFirst({ where: emailEnabled ? { - OR: [ - { - username: body.username.toLowerCase(), - }, - { - email: body.email?.toLowerCase(), - }, - ], + email: body.email?.toLowerCase(), emailVerified: { not: null }, } : { - username: body.username.toLowerCase(), + username: (body.username as string).toLowerCase(), }, }); @@ -86,8 +58,10 @@ export default async function Index( await prisma.user.create({ data: { name: body.name, - username: body.username.toLowerCase(), - email: body.email?.toLowerCase(), + username: emailEnabled + ? undefined + : (body.username as string).toLowerCase(), + email: emailEnabled ? body.email?.toLowerCase() : undefined, password: hashedPassword, }, }); diff --git a/pages/api/routes/users/index.ts b/pages/api/routes/users/index.ts index 2a1ecc1..7446150 100644 --- a/pages/api/routes/users/index.ts +++ b/pages/api/routes/users/index.ts @@ -32,7 +32,7 @@ export default async function users(req: NextApiRequest, res: NextApiResponse) { username: session.user.username, }); return res.status(users.status).json({ response: users.response }); - } else if (req.method === "PUT" && !req.body.password) { + } else if (req.method === "PUT") { const updated = await updateUser(req.body, session.user); return res.status(updated.status).json({ response: updated.response }); } diff --git a/pages/choose-username.tsx b/pages/choose-username.tsx new file mode 100644 index 0000000..7c426cb --- /dev/null +++ b/pages/choose-username.tsx @@ -0,0 +1,108 @@ +import SubmitButton from "@/components/SubmitButton"; +import { signOut } from "next-auth/react"; +import Image from "next/image"; +import { useEffect, useState } from "react"; +import { toast } from "react-hot-toast"; +import { useSession } from "next-auth/react"; +import { useRouter } from "next/router"; +import useAccountStore from "@/store/account"; + +export default function Subscribe() { + const [submitLoader, setSubmitLoader] = useState(false); + const [inputedUsername, setInputedUsername] = useState(""); + + const { data, status, update } = useSession(); + + const { updateAccount, account } = useAccountStore(); + + useEffect(() => { + console.log(data?.user); + }, [status]); + + async function submitUsername() { + setSubmitLoader(true); + + const redirectionToast = toast.loading("Applying..."); + + const response = await updateAccount({ + ...account, + username: inputedUsername, + }); + + if (response.ok) { + toast.success("Username Applied!"); + + update({ + id: data?.user.id, + }); + + signOut(); + } else toast.error(response.data as string); + toast.dismiss(redirectionToast); + setSubmitLoader(false); + } + + return ( + <> +One Last Step...
++ Please choose a username to start using your account. +
++ Username +
+ + setInputedUsername(e.target.value)} + className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" + /> ++ Note that you will have to log back in to complete the process. +
++ Feel free to reach out to us at{" "} + + hello@linkwarden.app + {" "} + in case of any issues. +
+- Username -
+ {emailEnabled ? undefined : ( ++ Username +
- setForm({ ...form, username: e.target.value })} - className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-500 duration-100" - /> -
- feel free to reach out to us at{" "}
+ Feel free to reach out to us at{" "}
hello@linkwarden.app
{" "}
diff --git a/prisma/migrations/20230715102805_init/migration.sql b/prisma/migrations/20230719181459_init/migration.sql
similarity index 99%
rename from prisma/migrations/20230715102805_init/migration.sql
rename to prisma/migrations/20230719181459_init/migration.sql
index 408f99f..1b7dfcf 100644
--- a/prisma/migrations/20230715102805_init/migration.sql
+++ b/prisma/migrations/20230719181459_init/migration.sql
@@ -30,7 +30,7 @@ CREATE TABLE "Session" (
CREATE TABLE "User" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,
- "username" TEXT NOT NULL,
+ "username" TEXT,
"email" TEXT,
"emailVerified" TIMESTAMP(3),
"image" TEXT,
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index a3882aa..43d8b90 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -38,7 +38,7 @@ model User {
id Int @id @default(autoincrement())
name String
- username String @unique
+ username String? @unique
email String? @unique
emailVerified DateTime?
diff --git a/store/account.ts b/store/account.ts
index ae08806..638848c 100644
--- a/store/account.ts
+++ b/store/account.ts
@@ -3,7 +3,7 @@ import { AccountSettings } from "@/types/global";
type ResponseObject = {
ok: boolean;
- data: object | string;
+ data: Omit