diff --git a/components/Shell.tsx b/components/Shell.tsx
index c13468bc..e51ff814 100644
--- a/components/Shell.tsx
+++ b/components/Shell.tsx
@@ -1,152 +1,268 @@
-import Link from 'next/link';
-import {useEffect, useState} from "react";
-import {useRouter} from "next/router";
-import {signOut, useSession} from 'next-auth/client';
-import {MenuIcon, XIcon} from '@heroicons/react/outline';
-import {collectPageParameters, telemetryEventTypes, useTelemetry} from "../lib/telemetry";
+import Link from "next/link";
+import { useEffect, useState } from "react";
+import { useRouter } from "next/router";
+import { signOut, useSession } from "next-auth/client";
+import { MenuIcon, XIcon } from "@heroicons/react/outline";
+import { collectPageParameters, telemetryEventTypes, useTelemetry } from "../lib/telemetry";
export default function Shell(props) {
- const router = useRouter();
- const [ session, loading ] = useSession();
- const [ profileDropdownExpanded, setProfileDropdownExpanded ] = useState(false);
- const [ mobileMenuExpanded, setMobileMenuExpanded ] = useState(false);
- let telemetry = useTelemetry();
+ const router = useRouter();
+ const [session, loading] = useSession();
+ const [profileDropdownExpanded, setProfileDropdownExpanded] = useState(false);
+ const [mobileMenuExpanded, setMobileMenuExpanded] = useState(false);
+ const telemetry = useTelemetry();
- useEffect(() => {
- telemetry.withJitsu((jitsu) => {
- return jitsu.track(telemetryEventTypes.pageView, collectPageParameters(router.pathname))
- });
- }, [telemetry])
+ useEffect(() => {
+ telemetry.withJitsu((jitsu) => {
+ return jitsu.track(telemetryEventTypes.pageView, collectPageParameters(router.pathname));
+ });
+ }, [telemetry]);
- const toggleProfileDropdown = () => {
- setProfileDropdownExpanded(!profileDropdownExpanded);
- }
+ const toggleProfileDropdown = () => {
+ setProfileDropdownExpanded(!profileDropdownExpanded);
+ };
- const toggleMobileMenu = () => {
- setMobileMenuExpanded(!mobileMenuExpanded);
- }
+ const toggleMobileMenu = () => {
+ setMobileMenuExpanded(!mobileMenuExpanded);
+ };
- const logoutHandler = () => {
- signOut({ redirect: false }).then( () => router.push('/auth/logout') );
- }
+ const logoutHandler = () => {
+ signOut({ redirect: false }).then(() => router.push("/auth/logout"));
+ };
- if ( ! loading && ! session ) {
- router.replace('/auth/login');
- }
+ if (!loading && !session) {
+ router.replace("/auth/login");
+ } else if (loading) {
+ return
Loading...
;
+ }
- return session && (
-
-
-
-));
\ No newline at end of file
+));
+
+UsernameInput.displayName = "UsernameInput";
+
+export { UsernameInput };
diff --git a/pages/settings/profile.tsx b/pages/settings/profile.tsx
index a00f9efa..c8cc0586 100644
--- a/pages/settings/profile.tsx
+++ b/pages/settings/profile.tsx
@@ -1,140 +1,173 @@
-import Head from 'next/head';
-import Link from 'next/link';
-import { useRef, useState } from 'react';
-import { useRouter } from 'next/router';
-import prisma from '../../lib/prisma';
-import Modal from '../../components/Modal';
-import Shell from '../../components/Shell';
-import SettingsShell from '../../components/Settings';
-import Avatar from '../../components/Avatar';
-import { signIn, useSession, getSession } from 'next-auth/client';
-import TimezoneSelect from 'react-timezone-select';
-import {UsernameInput} from "../../components/ui/UsernameInput";
+import { GetServerSideProps } from "next";
+import Head from "next/head";
+import { useRef, useState } from "react";
+import prisma 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 TimezoneSelect from "react-timezone-select";
+import { UsernameInput } from "../../components/ui/UsernameInput";
import ErrorAlert from "../../components/ui/alerts/Error";
export default function Settings(props) {
- const [ session, loading ] = useSession();
- const router = useRouter();
- const [successModalOpen, setSuccessModalOpen] = useState(false);
- const usernameRef = useRef
();
- const nameRef = useRef();
- const descriptionRef = useRef();
- const avatarRef = useRef();
+ const [successModalOpen, setSuccessModalOpen] = useState(false);
+ const usernameRef = useRef();
+ const nameRef = useRef();
+ const descriptionRef = useRef();
+ const avatarRef = useRef();
+ const [selectedTimeZone, setSelectedTimeZone] = useState({ value: props.user.timeZone });
+ const [selectedWeekStartDay, setSelectedWeekStartDay] = useState(props.user.weekStart || "Sunday");
- const [ selectedTimeZone, setSelectedTimeZone ] = useState({ value: props.user.timeZone });
- const [ selectedWeekStartDay, setSelectedWeekStartDay ] = useState(props.user.weekStart || 'Sunday');
+ const [hasErrors, setHasErrors] = useState(false);
+ const [errorMessage, setErrorMessage] = useState("");
- const [ hasErrors, setHasErrors ] = useState(false);
- const [ errorMessage, setErrorMessage ] = useState('');
+ const closeSuccessModal = () => {
+ setSuccessModalOpen(false);
+ };
- if (loading) {
- return Loading...
;
+ const handleError = async (resp) => {
+ if (!resp.ok) {
+ const error = await resp.json();
+ throw new Error(error.message);
}
+ };
- const closeSuccessModal = () => { setSuccessModalOpen(false); }
+ async function updateProfileHandler(event) {
+ event.preventDefault();
- const handleError = async (resp) => {
- if (!resp.ok) {
- const error = await resp.json();
- throw new Error(error.message);
- }
- }
+ const enteredUsername = usernameRef.current.value.toLowerCase();
+ const enteredName = nameRef.current.value;
+ const enteredDescription = descriptionRef.current.value;
+ const enteredAvatar = avatarRef.current.value;
+ const enteredTimeZone = selectedTimeZone.value;
+ const enteredWeekStartDay = selectedWeekStartDay;
- async function updateProfileHandler(event) {
- event.preventDefault();
+ // TODO: Add validation
- const enteredUsername = usernameRef.current.value;
- const enteredName = nameRef.current.value;
- const enteredDescription = descriptionRef.current.value;
- const enteredAvatar = avatarRef.current.value;
- const enteredTimeZone = selectedTimeZone.value;
- const enteredWeekStartDay = selectedWeekStartDay;
+ await fetch("/api/user/profile", {
+ method: "PATCH",
+ body: JSON.stringify({
+ username: enteredUsername,
+ name: enteredName,
+ description: enteredDescription,
+ avatar: enteredAvatar,
+ timeZone: enteredTimeZone,
+ weekStart: enteredWeekStartDay,
+ }),
+ headers: {
+ "Content-Type": "application/json",
+ },
+ })
+ .then(handleError)
+ .then(() => {
+ setSuccessModalOpen(true);
+ setHasErrors(false); // dismiss any open errors
+ })
+ .catch((err) => {
+ setHasErrors(true);
+ setErrorMessage(err.message);
+ });
+ }
- // TODO: Add validation
+ return (
+
+
+ Profile | Calendso
+
+
+
+
+
+
+
+
+ );
}
-export async function getServerSideProps(context) {
- const session = await getSession(context);
- if (!session) {
- return { redirect: { permanent: false, destination: '/auth/login' } };
- }
+export const getServerSideProps: GetServerSideProps = async (context) => {
+ const session = await getSession(context);
+ if (!session) {
+ return { redirect: { permanent: false, destination: "/auth/login" } };
+ }
- const user = await prisma.user.findFirst({
- where: {
- email: session.user.email,
- },
- select: {
- id: true,
- username: true,
- name: true,
- email: true,
- bio: true,
- avatar: true,
- timeZone: true,
- weekStart: true,
- }
- });
+ const user = await prisma.user.findFirst({
+ where: {
+ email: session.user.email,
+ },
+ select: {
+ id: true,
+ username: true,
+ name: true,
+ email: true,
+ bio: true,
+ avatar: true,
+ timeZone: true,
+ weekStart: true,
+ },
+ });
- return {
- props: {user}, // will be passed to the page component as props
- }
-}
\ No newline at end of file
+ return {
+ props: { user }, // will be passed to the page component as props
+ };
+};