v3: added user profile description
This commit is contained in:
@@ -34,6 +34,8 @@ import { DumpCreateModal } from "../components/DumpCreateModal.tsx";
|
||||
import { FollowUserButton } from "../components/FollowButton.tsx";
|
||||
import { ErrorCard } from "../components/ErrorCard.tsx";
|
||||
import { friendlyFetchError } from "../utils/apiError.ts";
|
||||
import { TextEditor } from "../components/TextEditor.tsx";
|
||||
import { Markdown } from "../components/Markdown.tsx";
|
||||
|
||||
const PAGE_SIZE = 20;
|
||||
|
||||
@@ -246,6 +248,11 @@ export function UserPublicProfile() {
|
||||
const [uploading, setUploading] = useState(false);
|
||||
const [avatarError, setAvatarError] = useState<string | null>(null);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const [descEditing, setDescEditing] = useState(false);
|
||||
const [descDraft, setDescDraft] = useState("");
|
||||
const [descSaving, setDescSaving] = useState(false);
|
||||
const [descError, setDescError] = useState<string | null>(null);
|
||||
const prevMyVotesRef = useRef<Set<string> | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -515,6 +522,36 @@ export function UserPublicProfile() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleDescSave = async () => {
|
||||
if (state.status !== "loaded") return;
|
||||
setDescSaving(true);
|
||||
setDescError(null);
|
||||
try {
|
||||
const res = await authFetch(`${API_URL}/api/users/me`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify({ description: descDraft.trim() }),
|
||||
});
|
||||
const body = await res.json();
|
||||
if (!res.ok || !body.success) {
|
||||
setDescError(body.error?.message ?? "Failed to save");
|
||||
return;
|
||||
}
|
||||
setState((s) =>
|
||||
s.status === "loaded"
|
||||
? {
|
||||
...s,
|
||||
user: { ...s.user, description: descDraft.trim() || undefined },
|
||||
}
|
||||
: s
|
||||
);
|
||||
setDescEditing(false);
|
||||
} catch {
|
||||
setDescError("Failed to save");
|
||||
} finally {
|
||||
setDescSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (state.status === "loading") {
|
||||
return (
|
||||
<PageShell>
|
||||
@@ -613,6 +650,76 @@ export function UserPublicProfile() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{(profileUser.description || isOwnProfile) && (
|
||||
<div className="profile-description">
|
||||
{descEditing
|
||||
? (
|
||||
<div className="profile-description-editor">
|
||||
<TextEditor
|
||||
className="comment-reply-textarea"
|
||||
value={descDraft}
|
||||
onChange={setDescDraft}
|
||||
onSubmit={handleDescSave}
|
||||
placeholder="Tell people about yourself…"
|
||||
autoResize
|
||||
/>
|
||||
<div className="profile-description-actions">
|
||||
<button
|
||||
type="button"
|
||||
className="btn-primary"
|
||||
onClick={handleDescSave}
|
||||
disabled={descSaving}
|
||||
>
|
||||
{descSaving ? "Saving…" : "Save"}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="btn-border"
|
||||
onClick={() => setDescEditing(false)}
|
||||
disabled={descSaving}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
{descError && (
|
||||
<ErrorCard title="Failed to save" message={descError} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<div
|
||||
className={`profile-description-view${
|
||||
isOwnProfile ? " profile-description-view--editable" : ""
|
||||
}`}
|
||||
onClick={isOwnProfile
|
||||
? () => {
|
||||
setDescDraft(profileUser.description ?? "");
|
||||
setDescError(null);
|
||||
setDescEditing(true);
|
||||
}
|
||||
: undefined}
|
||||
>
|
||||
{profileUser.description
|
||||
? (
|
||||
<Markdown className="profile-description-text">
|
||||
{profileUser.description}
|
||||
</Markdown>
|
||||
)
|
||||
: (
|
||||
<div className="profile-description-empty">
|
||||
Add a bio…
|
||||
</div>
|
||||
)}
|
||||
{isOwnProfile && (
|
||||
<span className="profile-description-edit-btn" aria-hidden>
|
||||
✎
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="profile-columns">
|
||||
<DumpList
|
||||
title={`Dumps (${dumps.items.length}${dumps.hasMore ? "+" : ""})`}
|
||||
|
||||
Reference in New Issue
Block a user