mirror of
https://github.com/hex248/sprint.git
synced 2026-02-07 18:23:03 +00:00
added UploadAvatar to login and account page
This commit is contained in:
@@ -4,11 +4,13 @@ import { SettingsPageLayout } from "@/components/settings-page-layout";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Field } from "@/components/ui/field";
|
import { Field } from "@/components/ui/field";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { UploadAvatar } from "@/components/upload-avatar";
|
||||||
import { user } from "@/lib/server";
|
import { user } from "@/lib/server";
|
||||||
|
|
||||||
function Account() {
|
function Account() {
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
|
const [avatarURL, setAvatarUrl] = useState<string | null>(null);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const [submitAttempted, setSubmitAttempted] = useState(false);
|
const [submitAttempted, setSubmitAttempted] = useState(false);
|
||||||
const [userId, setUserId] = useState<number | null>(null);
|
const [userId, setUserId] = useState<number | null>(null);
|
||||||
@@ -19,6 +21,7 @@ function Account() {
|
|||||||
const user = JSON.parse(userStr) as UserRecord;
|
const user = JSON.parse(userStr) as UserRecord;
|
||||||
setName(user.name);
|
setName(user.name);
|
||||||
setUserId(user.id);
|
setUserId(user.id);
|
||||||
|
setAvatarUrl(user.avatarURL || null);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -39,6 +42,7 @@ function Account() {
|
|||||||
id: userId,
|
id: userId,
|
||||||
name: name.trim(),
|
name: name.trim(),
|
||||||
password: password.trim(),
|
password: password.trim(),
|
||||||
|
avatarURL: avatarURL || undefined,
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
setError("");
|
setError("");
|
||||||
localStorage.setItem("user", JSON.stringify(data));
|
localStorage.setItem("user", JSON.stringify(data));
|
||||||
@@ -52,7 +56,11 @@ function Account() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsPageLayout title="Account">
|
<SettingsPageLayout title="Account">
|
||||||
<form onSubmit={handleSubmit} className="flex flex-col max-w-sm">
|
<form onSubmit={handleSubmit} className="flex flex-col gap-6 max-w-sm">
|
||||||
|
<div>
|
||||||
|
<Label className="mb-4 block">Avatar</Label>
|
||||||
|
<UploadAvatar avatarURL={avatarURL} onAvatarUploaded={setAvatarUrl} />
|
||||||
|
</div>
|
||||||
<Field
|
<Field
|
||||||
label="Full Name"
|
label="Full Name"
|
||||||
value={name}
|
value={name}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { ServerConfigurationDialog } from "@/components/server-configuration-dia
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Field } from "@/components/ui/field";
|
import { Field } from "@/components/ui/field";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { UploadAvatar } from "@/components/upload-avatar";
|
||||||
import { capitalise, cn, getServerURL } from "@/lib/utils";
|
import { capitalise, cn, getServerURL } from "@/lib/utils";
|
||||||
|
|
||||||
export default function LogInForm() {
|
export default function LogInForm() {
|
||||||
@@ -12,6 +13,7 @@ export default function LogInForm() {
|
|||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
|
const [avatarURL, setAvatarUrl] = useState<string | null>(null);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const [submitAttempted, setSubmitAttempted] = useState(false);
|
const [submitAttempted, setSubmitAttempted] = useState(false);
|
||||||
|
|
||||||
@@ -59,6 +61,7 @@ export default function LogInForm() {
|
|||||||
name,
|
name,
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
|
avatarURL,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
.then(async (res) => {
|
.then(async (res) => {
|
||||||
@@ -83,7 +86,7 @@ export default function LogInForm() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const focusFirstInput = () => {
|
const focusFirstInput = () => {
|
||||||
const firstInput = document.querySelector("input");
|
const firstInput = document.querySelector('input[type="text"]');
|
||||||
if (firstInput) {
|
if (firstInput) {
|
||||||
(firstInput as HTMLInputElement).focus();
|
(firstInput as HTMLInputElement).focus();
|
||||||
}
|
}
|
||||||
@@ -96,6 +99,7 @@ export default function LogInForm() {
|
|||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
setError("");
|
setError("");
|
||||||
setSubmitAttempted(false);
|
setSubmitAttempted(false);
|
||||||
|
setAvatarUrl(null);
|
||||||
requestAnimationFrame(() => focusFirstInput());
|
requestAnimationFrame(() => focusFirstInput());
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -119,32 +123,41 @@ export default function LogInForm() {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<ServerConfigurationDialog />
|
<ServerConfigurationDialog />
|
||||||
<span className="text-xl mb-2">{capitalise(mode)}</span>
|
<span className="text-xl ">{capitalise(mode)}</span>
|
||||||
|
|
||||||
{mode === "register" && (
|
<div className={"flex flex-col items-center mb-0"}>
|
||||||
|
{mode === "register" && (
|
||||||
|
<>
|
||||||
|
<UploadAvatar
|
||||||
|
avatarURL={avatarURL}
|
||||||
|
onAvatarUploaded={setAvatarUrl}
|
||||||
|
className={"mt-2 mb-4"}
|
||||||
|
/>
|
||||||
|
<Field
|
||||||
|
label="Full Name"
|
||||||
|
value={name}
|
||||||
|
onChange={(e) => setName(e.target.value)}
|
||||||
|
validate={(v) => (v.trim() === "" ? "Cannot be empty" : undefined)}
|
||||||
|
submitAttempted={submitAttempted}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<Field
|
<Field
|
||||||
label="Full Name"
|
label="Username"
|
||||||
value={name}
|
value={username}
|
||||||
onChange={(e) => setName(e.target.value)}
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
validate={(v) => (v.trim() === "" ? "Cannot be empty" : undefined)}
|
validate={(v) => (v.trim() === "" ? "Cannot be empty" : undefined)}
|
||||||
submitAttempted={submitAttempted}
|
submitAttempted={submitAttempted}
|
||||||
/>
|
/>
|
||||||
)}
|
<Field
|
||||||
<Field
|
label="Password"
|
||||||
label="Username"
|
value={password}
|
||||||
value={username}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
onChange={(e) => setUsername(e.target.value)}
|
validate={(v) => (v.trim() === "" ? "Cannot be empty" : undefined)}
|
||||||
validate={(v) => (v.trim() === "" ? "Cannot be empty" : undefined)}
|
hidden={true}
|
||||||
submitAttempted={submitAttempted}
|
submitAttempted={submitAttempted}
|
||||||
/>
|
/>
|
||||||
<Field
|
</div>
|
||||||
label="Password"
|
|
||||||
value={password}
|
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
|
||||||
validate={(v) => (v.trim() === "" ? "Cannot be empty" : undefined)}
|
|
||||||
hidden={true}
|
|
||||||
submitAttempted={submitAttempted}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{mode === "login" ? (
|
{mode === "login" ? (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -2,15 +2,18 @@ import { useRef, useState } from "react";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { user } from "@/lib/server";
|
import { user } from "@/lib/server";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export function UploadAvatar({
|
export function UploadAvatar({
|
||||||
avatarURL,
|
avatarURL,
|
||||||
onAvatarUploaded,
|
onAvatarUploaded,
|
||||||
label,
|
label,
|
||||||
|
className,
|
||||||
}: {
|
}: {
|
||||||
avatarURL?: string | null;
|
avatarURL?: string | null;
|
||||||
onAvatarUploaded: (avatarURL: string) => void;
|
onAvatarUploaded: (avatarURL: string) => void;
|
||||||
label?: string;
|
label?: string;
|
||||||
|
className?: string;
|
||||||
}) {
|
}) {
|
||||||
const [uploading, setUploading] = useState(false);
|
const [uploading, setUploading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
@@ -37,7 +40,7 @@ export function UploadAvatar({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-4">
|
<div className={cn("flex items-center gap-4", className)}>
|
||||||
{avatarURL && (
|
{avatarURL && (
|
||||||
<img src={avatarURL} alt="Avatar" className="w-16 h-16 rounded-full border object-cover" />
|
<img src={avatarURL} alt="Avatar" className="w-16 h-16 rounded-full border object-cover" />
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user