apply suggestions
continuous-integration/drone/push Build is passing Details

maxime 1 year ago
parent d6f1a633a1
commit 7b4a06a932

@ -8,21 +8,6 @@
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>
<script
src="https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js"
crossorigin></script>
<script
src="https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.production.min.js"
crossorigin></script>
<script
src="https://cdn.jsdelivr.net/npm/react-bootstrap@next/dist/react-bootstrap.min.js"
crossorigin></script>
<script>
var Alert = ReactBootstrap.Alert
</script>
<script type="module" src="/src/main.tsx"></script> <script type="module" src="/src/main.tsx"></script>
</body> </body>
</html> </html>

@ -45,8 +45,7 @@ export default function App() {
) )
} }
const storedAuth = useMemo(() => getStoredAuthentication(), []) const fetcher = useMemo(() => new Fetcher(getStoredAuthentication()), [])
const fetcher = useMemo(() => new Fetcher(storedAuth), [storedAuth])
const [user, setUser] = useState<User | null>(null) const [user, setUser] = useState<User | null>(null)
const handleAuthSuccess = useCallback( const handleAuthSuccess = useCallback(
@ -247,7 +246,7 @@ function AppLayout() {
interface UserContext { interface UserContext {
user: User | null user: User | null
setUser: (user: User) => void setUser: (user: User | null) => void
} }
const SignedInUserContext = createContext<UserContext | null>(null) const SignedInUserContext = createContext<UserContext | null>(null)
@ -257,7 +256,7 @@ export function useAppFetcher() {
return useContext(FetcherContext) return useContext(FetcherContext)
} }
export function useUser(): [User | null, (user: User) => void] { export function useUser(): [User | null, (user: User | null) => void] {
const { user, setUser } = useContext(SignedInUserContext)! const { user, setUser } = useContext(SignedInUserContext)!
return [user, setUser] return [user, setUser]
} }

@ -68,11 +68,9 @@ export class Fetcher {
} }
const nextToken = response.headers.get("Next-Authorization")! const nextToken = response.headers.get("Next-Authorization")!
const expirationDate = new Date( const expirationDate = response.headers.get("Next-Authorization-Expiration-Date")!
response.headers.get("Next-Authorization-Expiration-Date")!,
)
if (nextToken && expirationDate) { if (nextToken && expirationDate) {
this.auth = { token: nextToken, expirationDate } this.auth = { token: nextToken, expirationDate: new Date(expirationDate) }
} }
return response return response

@ -1,4 +1,4 @@
import { FormEvent, useCallback, useRef, useState } from "react" import { FormEvent, useCallback, useEffect, useRef, useState } from "react"
import "../style/settings.css" import "../style/settings.css"
import { useAppFetcher, useUser } from "../App.tsx" import { useAppFetcher, useUser } from "../App.tsx"
import { Fetcher } from "../app/Fetcher.ts" import { Fetcher } from "../app/Fetcher.ts"
@ -10,18 +10,19 @@ export default function ProfileSettings() {
const [errorMessages, setErrorMessages] = useState<string[]>([]) const [errorMessages, setErrorMessages] = useState<string[]>([])
const [success, setSuccess] = useState(false) const [success, setSuccess] = useState(false)
const formRef = useRef<HTMLFormElement | null>(null) const [name, setName] = useState(user!.name)
const [email, setEmail] = useState(user!.email)
const [password, setPassword] = useState<string>()
const [confirmPassword, setConfirmPassword] = useState<string>()
const passwordConfirmRef = useRef<HTMLInputElement>(null)
const formRef = useRef<HTMLFormElement>(null)
const submitForm = useCallback( const submitForm = useCallback(
async (e: FormEvent) => { async (e: FormEvent) => {
e.preventDefault() e.preventDefault()
const { name, email, password, confirmPassword } =
Object.fromEntries<string>(
new FormData(formRef.current!) as Iterable<
[PropertyKey, string]
>,
)
passwordConfirmRef.current!.checkValidity()
if (password !== confirmPassword) { if (password !== confirmPassword) {
setErrorMessages(["Les mots de passe ne correspondent pas !"]) setErrorMessages(["Les mots de passe ne correspondent pas !"])
return return
@ -46,8 +47,14 @@ export default function ProfileSettings() {
formRef.current!.reset() formRef.current!.reset()
setErrorMessages([]) setErrorMessages([])
}, },
[fetcher, setUser, user], [confirmPassword, email, fetcher, name, password, setUser, user],
)
useEffect(() => {
passwordConfirmRef.current!.setCustomValidity(
password === confirmPassword ? "" : "Les mots de passe ne correspondent pas !"
) )
}, [confirmPassword, password])
const [modalShow, setModalShow] = useState(false) const [modalShow, setModalShow] = useState(false)
const width = 150 const width = 150
@ -94,44 +101,64 @@ export default function ProfileSettings() {
ref={formRef} ref={formRef}
id="credentials-form" id="credentials-form"
onSubmit={submitForm}> onSubmit={submitForm}>
<p>Nom d'utilisateur</p> <label htmlFor="name">Nom d'utilisateur</label>
<input <input
className="settings-input" className="settings-input"
id="name"
name="name" name="name"
type="text" type="text"
placeholder={"Nom d'utilisateur"} autoComplete="username"
defaultValue={user!.name} required
placeholder="Nom d'utilisateur"
value={name}
onChange={e => setName(e.target.value)}
/> />
<p>Addresse email</p> <label htmlFor="email">Adresse email</label>
<input <input
className="settings-input" className="settings-input"
name="email" name="email"
id="email"
type="email" type="email"
placeholder={"Addresse email"} placeholder={"Addresse email"}
defaultValue={user!.email} autoComplete="email"
required
value={email}
onChange={e => setEmail(e.target.value)}
/> />
<p>Mot de passe</p> <label htmlFor="password">Mot de passe</label>
<input <input
className="settings-input" className="settings-input"
name="password" name="password"
id={"password"}
type="password" type="password"
placeholder={"Mot de passe"} placeholder={"Mot de passe"}
autoComplete="new-password"
value={password}
onChange={e => setPassword(e.target.value)}
/> />
<p>Confirmez le mot de passe</p> <label htmlFor="confirmPassword">Confirmez le mot de passe</label>
<input <input
ref={passwordConfirmRef}
className="settings-input" className="settings-input"
name="confirmPassword" name="confirmPassword"
id="confirmPassword"
type="password" type="password"
autoComplete="new-password"
placeholder={"Confirmation du mot de passe"} placeholder={"Confirmation du mot de passe"}
value={confirmPassword}
onChange={e => setConfirmPassword(e.target.value)}
/> />
<button <button
className="settings-button" className="settings-button"
type="submit" type="submit">
onClick={submitForm}>
Mettre à jour Mettre à jour
</button> </button>
</form> </form>
@ -173,11 +200,38 @@ function ProfileImageInputPopup({ show, onHide }: ProfileImageInputPopupProps) {
const fetcher = useAppFetcher() const fetcher = useAppFetcher()
const [user, setUser] = useUser() const [user, setUser] = useUser()
const [link, setLink] = useState("")
useEffect(() => {
function onKeyUp(e: KeyboardEvent) {
if (e.key === "Escape") onHide()
}
window.addEventListener('keyup', onKeyUp)
return () => window.removeEventListener('keyup', onKeyUp)
}, [onHide])
const handleForm = useCallback(async (e: FormEvent) => {
e.preventDefault()
const url = urlRef.current!.value
const errors = await updateAccount(fetcher, {
profilePicture: url,
})
if (errors.length !== 0) {
setErrorMessages(errors)
return
}
setUser({ ...user!, profilePicture: url })
setErrorMessages([])
onHide()
}, [fetcher, onHide, setUser, user])
if (!show) return <></> if (!show) return <></>
return ( return (
<div id="profile-picture-popup"> <dialog id="profile-picture-popup">
<div id="profile-picture-popup-content"> <form id="profile-picture-popup-form" onSubmit={handleForm}>
<div id="profile-picture-popup-header"> <div id="profile-picture-popup-header">
<p id="profile-picture-popup-title"> <p id="profile-picture-popup-title">
Nouvelle photo de profil Nouvelle photo de profil
@ -189,9 +243,9 @@ function ProfileImageInputPopup({ show, onHide }: ProfileImageInputPopupProps) {
{msg} {msg}
</div> </div>
))} ))}
<p id="profile-picture-popup-subtitle"> <label id="profile-picture-popup-subtitle" htmlFor="profile-picture">
Saisissez le lien vers votre nouvelle photo de profil Saisissez le lien vers votre nouvelle photo de profil
</p> </label>
<input <input
className={ className={
`settings-input ` + `settings-input ` +
@ -199,33 +253,26 @@ function ProfileImageInputPopup({ show, onHide }: ProfileImageInputPopupProps) {
? "" ? ""
: "invalid-input") : "invalid-input")
} }
id="profile-picture"
ref={urlRef} ref={urlRef}
type="input" type="url"
autoComplete="url"
required
placeholder={"lien vers une image"} placeholder={"lien vers une image"}
value={link}
onChange={e => setLink(e.target.value)}
/> />
<div id="profile-picture-popup-footer"> <div id="profile-picture-popup-footer">
<button className={"settings-button"} onClick={onHide}> <button className={"settings-button"} onClick={onHide}>
Annuler Annuler
</button> </button>
<button <input
type="submit"
className={"settings-button"} className={"settings-button"}
onClick={async () => { value="Valider"
const url = urlRef.current!.value />
const errors = await updateAccount(fetcher, {
profilePicture: url,
})
if (errors.length !== 0) {
setErrorMessages(errors)
return
}
setUser({ ...user!, profilePicture: url })
setErrorMessages([])
onHide()
}}>
Valider
</button>
</div>
</div>
</div> </div>
</form>
</dialog>
) )
} }

@ -11,7 +11,7 @@ export function Header() {
<img <img
id="img-account" id="img-account"
src={user.profilePicture} src={user.profilePicture}
alt={"profile-picture"} alt={`Photo de profil de ${user!.name}`}
/> />
) : ( ) : (
<AccountSvg id="img-account" /> <AccountSvg id="img-account" />

@ -20,13 +20,13 @@ body {
#body { #body {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
margin: 0px; margin: 0;
height: 100%; height: 100%;
background-color: var(--home-second-color); background-color: var(--home-second-color);
} }
.data { .data {
border: 1.5px solid var(--main-contrast-color); border: 2px solid var(--main-contrast-color);
background-color: var(--home-main-color); background-color: var(--home-main-color);
border-radius: 0.75cap; border-radius: 0.75cap;
color: var(--main-contrast-color); color: var(--main-contrast-color);

@ -79,7 +79,7 @@
background-color: rgba(84, 78, 78, 0.33); background-color: rgba(84, 78, 78, 0.33);
} }
#profile-picture-popup-content { #profile-picture-popup-form {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
row-gap: 20px; row-gap: 20px;

@ -40,12 +40,6 @@
color: var(--accent-color); color: var(--accent-color);
} }
#username {
text-align: center;
vertical-align: center;
margin: 0;
}
#clickable-header-right { #clickable-header-right {
border-radius: 1cap; border-radius: 1cap;

Loading…
Cancel
Save