-
-
-
{props.user.name}
-
- {props.eventType.title}
-
-
-
- {props.eventType.length} minutes
-
- {selectedLocation === LocationType.InPerson && (
+
+
+
+
+
+
{props.user.name}
+
+ {props.eventType.title}
+
-
- {locationInfo(selectedLocation).address}
+
+ {props.eventType.length} minutes
- )}
-
-
- {preferredTimeZone &&
- dayjs(date)
- .tz(preferredTimeZone)
- .format((is24h ? "H:mm" : "h:mma") + ", dddd DD MMMM YYYY")}
-
-
{props.eventType.description}
-
-
+
+
- {error && (
-
-
-
-
-
-
- )}
+ {locations.length > 1 && (
+
+ Location
+ {locations.map((location) => (
+
+ ))}
+
+ )}
+ {selectedLocation === LocationType.Phone && (
+
+
+
+
{
+ /* DO NOT REMOVE: Callback required by PhoneInput, comment added to satisfy eslint:no-empty-function */
+ }}
+ />
+
+
+ )}
+ {props.eventType.customInputs &&
+ props.eventType.customInputs
+ .sort((a, b) => a.id - b.id)
+ .map((input) => (
+
+ ))}
+
+
+
+
+
+
+
+
Cancel
+
+
+
+ {error && (
+
+ )}
+
-
-
-
+
+
+ )
);
}
export async function getServerSideProps(context) {
- const user = await prisma.user.findFirst({
- where: {
+ const user = await whereAndSelect(
+ prisma.user.findFirst,
+ {
username: context.query.user,
},
- select: {
- username: true,
- name: true,
- email: true,
- bio: true,
- avatar: true,
- eventTypes: true,
- },
- });
+ ["username", "name", "email", "bio", "avatar", "eventTypes", "theme"]
+ );
const eventType = await prisma.eventType.findUnique({
where: {
diff --git a/pages/api/user/profile.ts b/pages/api/user/profile.ts
index dfb13315..fbc13c7d 100644
--- a/pages/api/user/profile.ts
+++ b/pages/api/user/profile.ts
@@ -1,27 +1,28 @@
-import type { NextApiRequest, NextApiResponse } from 'next';
-import { getSession } from 'next-auth/client';
-import prisma from '../../../lib/prisma';
+import type { NextApiRequest, NextApiResponse } from "next";
+import { getSession } from "next-auth/client";
+import prisma, { whereAndSelect } from "@lib/prisma";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
- const session = await getSession({req: req});
+ const session = await getSession({ req: req });
if (!session) {
- res.status(401).json({message: "Not authenticated"});
- return;
+ res.status(401).json({ message: "Not authenticated" });
+ return;
}
// Get user
- const user = await prisma.user.findUnique({
- where: {
- email: session.user.email,
+ const user = await whereAndSelect(
+ prisma.user.findUnique,
+ {
+ id: session.user.id,
},
- select: {
- id: true,
- password: true
- }
- });
+ ["id", "password"]
+ );
- if (!user) { res.status(404).json({message: 'User not found'}); return; }
+ if (!user) {
+ res.status(404).json({ message: "User not found" });
+ return;
+ }
const username = req.body.username;
// username is changed: username is optional but it is necessary to be unique, enforce here
@@ -29,10 +30,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const userConflict = await prisma.user.findFirst({
where: {
username,
- }
+ },
});
if (userConflict) {
- return res.status(409).json({ message: 'Username already taken' });
+ return res.status(409).json({ message: "Username already taken" });
}
}
@@ -42,8 +43,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const timeZone = req.body.timeZone;
const weekStart = req.body.weekStart;
const hideBranding = req.body.hideBranding;
+ const theme = req.body.theme;
- const updateUser = await prisma.user.update({
+ await prisma.user.update({
where: {
id: user.id,
},
@@ -52,11 +54,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
name,
avatar,
bio: description,
- timeZone: timeZone,
- weekStart: weekStart,
- hideBranding: hideBranding,
+ timeZone,
+ weekStart,
+ hideBranding,
+ theme,
},
});
- return res.status(200).json({message: 'Profile updated successfully'});
-}
\ No newline at end of file
+ return res.status(200).json({ message: "Profile updated successfully" });
+}
diff --git a/pages/settings/profile.tsx b/pages/settings/profile.tsx
index 8278a55c..6f7836eb 100644
--- a/pages/settings/profile.tsx
+++ b/pages/settings/profile.tsx
@@ -1,12 +1,13 @@
import { GetServerSideProps } from "next";
import Head from "next/head";
-import { useRef, useState } from "react";
-import prisma from "../../lib/prisma";
+import { useEffect, useRef, useState } from "react";
+import prisma, { whereAndSelect } from "@lib/prisma";
import Modal from "../../components/Modal";
import Shell from "../../components/Shell";
import SettingsShell from "../../components/Settings";
import Avatar from "../../components/Avatar";
import { getSession } from "next-auth/client";
+import Select from "react-select";
import TimezoneSelect from "react-timezone-select";
import { UsernameInput } from "../../components/ui/UsernameInput";
import ErrorAlert from "../../components/ui/alerts/Error";
@@ -18,12 +19,25 @@ export default function Settings(props) {
const descriptionRef = useRef
();
const avatarRef = useRef();
const hideBrandingRef = useRef();
+ const [selectedTheme, setSelectedTheme] = useState({ value: "" });
const [selectedTimeZone, setSelectedTimeZone] = useState({ value: props.user.timeZone });
- const [selectedWeekStartDay, setSelectedWeekStartDay] = useState(props.user.weekStart || "Sunday");
+ const [selectedWeekStartDay, setSelectedWeekStartDay] = useState({ value: "" });
const [hasErrors, setHasErrors] = useState(false);
const [errorMessage, setErrorMessage] = useState("");
+ const themeOptions = [
+ { value: "light", label: "Light" },
+ { value: "dark", label: "Dark" },
+ ];
+
+ useEffect(() => {
+ setSelectedTheme(
+ props.user.theme ? themeOptions.find((theme) => theme.value === props.user.theme) : null
+ );
+ setSelectedWeekStartDay({ value: props.user.weekStart, label: props.user.weekStart });
+ }, []);
+
const closeSuccessModal = () => {
setSuccessModalOpen(false);
};
@@ -43,7 +57,7 @@ export default function Settings(props) {
const enteredDescription = descriptionRef.current.value;
const enteredAvatar = avatarRef.current.value;
const enteredTimeZone = selectedTimeZone.value;
- const enteredWeekStartDay = selectedWeekStartDay;
+ const enteredWeekStartDay = selectedWeekStartDay.value;
const enteredHideBranding = hideBrandingRef.current.checked;
// TODO: Add validation
@@ -58,6 +72,7 @@ export default function Settings(props) {
timeZone: enteredTimeZone,
weekStart: enteredWeekStartDay,
hideBranding: enteredHideBranding,
+ theme: selectedTheme ? selectedTheme.value : null,
}),
headers: {
"Content-Type": "application/json",
@@ -124,9 +139,8 @@ export default function Settings(props) {
name="about"
placeholder="A little something about yourself."
rows={3}
- className="shadow-sm focus:ring-blue-500 focus:border-blue-500 mt-1 block w-full sm:text-sm border-gray-300 rounded-md">
- {props.user.bio}
-
+ defaultValue={props.user.bio}
+ className="shadow-sm focus:ring-blue-500 focus:border-blue-500 mt-1 block w-full sm:text-sm border-gray-300 rounded-md">