Added handle editing with warning.
This commit is contained in:
parent
8d08cc435a
commit
72e7a8fd6e
2 changed files with 134 additions and 3 deletions
|
@ -4,6 +4,7 @@ import { useRefresh } from "../../../lib/RefreshContext";
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
did: string;
|
did: string;
|
||||||
|
handle?: string;
|
||||||
displayName?: string;
|
displayName?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
avatar?: {
|
avatar?: {
|
||||||
|
@ -14,6 +15,7 @@ interface User {
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface RepoResponse {
|
interface RepoResponse {
|
||||||
cursor: string;
|
cursor: string;
|
||||||
repos: {
|
repos: {
|
||||||
|
@ -79,6 +81,16 @@ export default function UserList() {
|
||||||
show: false,
|
show: false,
|
||||||
user: null,
|
user: null,
|
||||||
});
|
});
|
||||||
|
const [editModal, setEditModal] = useState<{
|
||||||
|
show: boolean;
|
||||||
|
user: User | null;
|
||||||
|
newHandle: string;
|
||||||
|
}>({
|
||||||
|
show: false,
|
||||||
|
user: null,
|
||||||
|
newHandle: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
const resetState = () => {
|
const resetState = () => {
|
||||||
setUsers([]);
|
setUsers([]);
|
||||||
|
@ -108,6 +120,7 @@ export default function UserList() {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
return {
|
return {
|
||||||
did,
|
did,
|
||||||
|
handle: data.value.handle,
|
||||||
displayName: data.value.displayName,
|
displayName: data.value.displayName,
|
||||||
description: data.value.description,
|
description: data.value.description,
|
||||||
avatar: data.value.avatar,
|
avatar: data.value.avatar,
|
||||||
|
@ -210,6 +223,48 @@ export default function UserList() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateUserHandle = async (did: string, newHandle: string) => {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
const baseUrl = await Settings.getServiceUrl();
|
||||||
|
if (!baseUrl) throw new Error("Service URL not configured");
|
||||||
|
|
||||||
|
const headers = {
|
||||||
|
Authorization: await getAuthHeader(),
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
`${baseUrl}/xrpc/com.atproto.admin.updateAccountHandle`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers,
|
||||||
|
body: JSON.stringify({
|
||||||
|
did,
|
||||||
|
handle: newHandle,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorText = await response.text();
|
||||||
|
console.error("Error response:", errorText);
|
||||||
|
throw new Error(
|
||||||
|
`Failed to update handle: ${response.status} ${response.statusText}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await fetchUsers(); // Refresh the user list after successful update
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Update handle error:", err);
|
||||||
|
setError(err instanceof Error ? err.message : "Failed to update handle");
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function checkSettings() {
|
async function checkSettings() {
|
||||||
try {
|
try {
|
||||||
|
@ -304,6 +359,69 @@ export default function UserList() {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Edit Handle Modal */}
|
||||||
|
{editModal.show && editModal.user && (
|
||||||
|
<dialog className="modal modal-open">
|
||||||
|
<div className="modal-box">
|
||||||
|
<h3 className="font-bold text-lg">Edit Handle</h3>
|
||||||
|
<p className="py-4">
|
||||||
|
Update handle for{" "}
|
||||||
|
<span className="font-semibold">
|
||||||
|
{editModal.user.displayName || "Anonymous"}
|
||||||
|
</span>.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<span className="font-bold">**Note that you will need a "_atproto" TXT record with the corresponding "did=SOME_DID_NUMBER" before changing your handle to a subdomain of your PDS domain.</span>
|
||||||
|
</p>
|
||||||
|
<div className="form-control">
|
||||||
|
<label className="label">
|
||||||
|
<span className="label-text">New Handle</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="new.handle.pds.domain"
|
||||||
|
className="input input-bordered"
|
||||||
|
value={editModal.newHandle}
|
||||||
|
onChange={(e) =>
|
||||||
|
setEditModal({ ...editModal, newHandle: e.target.value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="modal-action">
|
||||||
|
<button
|
||||||
|
className="btn"
|
||||||
|
onClick={() =>
|
||||||
|
setEditModal({ show: false, user: null, newHandle: "" })
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="btn btn-primary"
|
||||||
|
onClick={async () => {
|
||||||
|
if (editModal.user && editModal.newHandle) {
|
||||||
|
await updateUserHandle(editModal.user.did, editModal.newHandle);
|
||||||
|
setEditModal({ show: false, user: null, newHandle: "" });
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={!editModal.newHandle}
|
||||||
|
>
|
||||||
|
Update Handle
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form method="dialog" className="modal-backdrop">
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
setEditModal({ show: false, user: null, newHandle: "" })
|
||||||
|
}
|
||||||
|
>
|
||||||
|
close
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Confirmation Modal */}
|
{/* Confirmation Modal */}
|
||||||
{deleteConfirmation.show && deleteConfirmation.user && (
|
{deleteConfirmation.show && deleteConfirmation.user && (
|
||||||
<dialog className="modal modal-open">
|
<dialog className="modal modal-open">
|
||||||
|
@ -396,6 +514,9 @@ export default function UserList() {
|
||||||
<h2 className="text-lg font-semibold">
|
<h2 className="text-lg font-semibold">
|
||||||
{user.displayName || "Anonymous"}
|
{user.displayName || "Anonymous"}
|
||||||
</h2>
|
</h2>
|
||||||
|
<div className="font-mono text-sm opacity-70 mt-1">
|
||||||
|
{user.handle}
|
||||||
|
</div>
|
||||||
<div className="font-mono text-sm opacity-70 mt-1">
|
<div className="font-mono text-sm opacity-70 mt-1">
|
||||||
{user.did}
|
{user.did}
|
||||||
</div>
|
</div>
|
||||||
|
@ -405,11 +526,21 @@ export default function UserList() {
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<button
|
<button
|
||||||
onClick={() =>
|
onClick={() => setEditModal({
|
||||||
setDeleteConfirmation({ show: true, user })
|
show: true,
|
||||||
}
|
user,
|
||||||
|
newHandle: user.handle || ""
|
||||||
|
})}
|
||||||
|
className="btn btn-sm btn-primary"
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setDeleteConfirmation({ show: true, user })}
|
||||||
className="btn btn-sm btn-error"
|
className="btn btn-sm btn-error"
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
>
|
>
|
||||||
|
|
Loading…
Add table
Reference in a new issue