/
EditUsername.tsx
117 lines (106 loc) · 3.43 KB
/
EditUsername.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
'use client';
import { FormEvent, useState } from 'react';
import editUsernameAction, { EditUsernameActionT } from './editUsernameAction';
import { useSession } from 'next-auth/react';
import { useRouter } from 'next/navigation';
type Props = {
username: string;
};
export default function EditUsername({ username }: Props) {
const [edit, setEdit] = useState(false);
const [newUsername, setNewUsername] = useState(username);
const [error, setError] = useState<null | string>(null);
const [message, setMessage] = useState<null | string>(null);
const [loading, setLoading] = useState(false);
const { update } = useSession();
const router = useRouter();
async function handleSubmit(e: FormEvent) {
e.preventDefault();
setLoading(true);
// validate newUsername
if (newUsername === '' || newUsername.length < 4) {
setError('Username is too short.');
setLoading(false);
return;
}
// call server action
const actionResponse: EditUsernameActionT = await editUsernameAction(
newUsername
);
// screen flicker only in dev mode because of revalidateTags in editUsernameAction
// handle error
if (actionResponse.error) {
setError(actionResponse.message);
setMessage(actionResponse.message);
setLoading(false);
return;
}
// handle success
// username is updated in DB and getCurrentUser fetch was updated with revalidateTag
if (!actionResponse.error && actionResponse.message === 'Success') {
// inform user of success
setError(null);
setMessage('Updated username.');
setLoading(false);
// update NextAuth token
await update({ username: actionResponse.data.username });
// refresh server components
router.refresh();
}
}
return (
<div className='mb-2'>
<form onSubmit={handleSubmit}>
<label htmlFor='username' className='block italic'>
Username:
</label>
<div className='flex gap-1'>
{!edit && <div>{username}</div>}
{edit && (
<>
<input
type='text'
className='bg-white border border-zinc-300 rounded-sm px-2 py-1 w-48'
required
name='username'
id='username'
value={newUsername}
onChange={(e) => setNewUsername(e.target.value)}
/>
<button
type='submit'
className={`bg-blue-400 px-3 py-1 rounded-md disabled:bg-sky-200 disabled:text-gray-400 disabled:cursor-wait`}
disabled={loading}
aria-disabled={loading}
>
{loading ? 'saving' : 'save'}
</button>
</>
)}
<button
type='button'
onClick={() => {
setEdit((prev) => !prev);
setError(null);
setMessage(null);
setNewUsername(username);
}}
className='underline text-sky-700 ml-1'
>
{edit ? 'close' : 'edit'}
</button>
</div>
{edit && error && (
<div className='text-red-700' aria-live='polite'>
Something went wrong: {error}
</div>
)}
{edit && !error && message ? (
<div className='text-green-700' aria-live='polite'>
{message}
</div>
) : null}
</form>
</div>
);
}