diff --git a/components/ui/UsernameInput.tsx b/components/ui/UsernameInput.tsx
new file mode 100644
index 0000000000..31d2ba0333
--- /dev/null
+++ b/components/ui/UsernameInput.tsx
@@ -0,0 +1,17 @@
+import React from "react";
+
+export const UsernameInput = React.forwardRef( (props, ref) => (
+ // todo, check if username is already taken here?
+
+
+
+
+ {typeof window !== "undefined" && window.location.hostname}/
+
+
+
+
+));
\ No newline at end of file
diff --git a/components/ui/alerts/Error.tsx b/components/ui/alerts/Error.tsx
new file mode 100644
index 0000000000..8cc239988d
--- /dev/null
+++ b/components/ui/alerts/Error.tsx
@@ -0,0 +1,22 @@
+
+import { XCircleIcon } from '@heroicons/react/solid'
+
+export default function ErrorAlert(props) {
+ return (
+
+
+
+
+
+
+
Something went wrong
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/pages/api/user/profile.ts b/pages/api/user/profile.ts
index f1b2e18d68..fb47f5d221 100644
--- a/pages/api/user/profile.ts
+++ b/pages/api/user/profile.ts
@@ -3,46 +3,58 @@ import { getSession } from 'next-auth/client';
import prisma 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;
+ if (!session) {
+ res.status(401).json({message: "Not authenticated"});
+ return;
+ }
+
+ // Get user
+ const user = await prisma.user.findUnique({
+ where: {
+ email: session.user.email,
+ },
+ select: {
+ id: true,
+ password: true
}
+ });
- // Get user
- const user = await prisma.user.findFirst({
- where: {
- email: session.user.email,
- },
- select: {
- id: true,
- password: true
- }
+ 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
+ if (username !== user.username) {
+ const userConflict = await prisma.user.findFirst({
+ where: {
+ username,
+ }
});
+ if (userConflict) {
+ return res.status(409).json({ message: 'Username already taken' });
+ }
+ }
- if (!user) { res.status(404).json({message: 'User not found'}); return; }
+ const name = req.body.name;
+ const description = req.body.description;
+ const avatar = req.body.avatar;
+ const timeZone = req.body.timeZone;
+ const weekStart = req.body.weekStart;
- const username = req.body.username;
- const name = req.body.name;
- const description = req.body.description;
- const avatar = req.body.avatar;
- const timeZone = req.body.timeZone;
- const weekStart = req.body.weekStart;
+ const updateUser = await prisma.user.update({
+ where: {
+ id: user.id,
+ },
+ data: {
+ username,
+ name,
+ avatar,
+ bio: description,
+ timeZone: timeZone,
+ weekStart: weekStart,
+ },
+ });
- const updateUser = await prisma.user.update({
- where: {
- id: user.id,
- },
- data: {
- username,
- name,
- avatar,
- bio: description,
- timeZone: timeZone,
- weekStart: weekStart,
- },
- });
-
- res.status(200).json({message: 'Profile updated successfully'});
+ return res.status(200).json({message: 'Profile updated successfully'});
}
\ No newline at end of file
diff --git a/pages/settings/profile.tsx b/pages/settings/profile.tsx
index d0a112943b..2078796636 100644
--- a/pages/settings/profile.tsx
+++ b/pages/settings/profile.tsx
@@ -9,6 +9,8 @@ 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 ErrorAlert from "../../components/ui/alerts/Error";
export default function Settings(props) {
const [ session, loading ] = useSession();
@@ -22,12 +24,22 @@ export default function Settings(props) {
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('');
+
if (loading) {
return Loading...
;
}
const closeSuccessModal = () => { setSuccessModalOpen(false); }
+ const handleError = async (resp) => {
+ if (!resp.ok) {
+ const error = await resp.json();
+ throw new Error(error.message);
+ }
+ }
+
async function updateProfileHandler(event) {
event.preventDefault();
@@ -46,10 +58,10 @@ export default function Settings(props) {
headers: {
'Content-Type': 'application/json'
}
+ }).then(handleError).then( () => setSuccessModalOpen(true) ).catch( (err) => {
+ setHasErrors(true);
+ setErrorMessage(err.message);
});
-
- router.replace(router.asPath);
- setSuccessModalOpen(true);
}
return(
@@ -60,6 +72,7 @@ export default function Settings(props) {