This commit is contained in:
2026-05-10 22:20:54 +08:00
parent d6219f1a0c
commit 192accd796
92 changed files with 7045 additions and 1559 deletions

View File

@@ -28,6 +28,7 @@ export function AdminInviteCodePage({
const [inviteCode, setInviteCode] = useState('');
const [startsAt, setStartsAt] = useState('');
const [expiresAt, setExpiresAt] = useState('');
const [grantedTagsText, setGrantedTagsText] = useState('');
const [metadataText, setMetadataText] = useState('{}');
const [errorMessage, setErrorMessage] = useState('');
const [listErrorMessage, setListErrorMessage] = useState('');
@@ -80,6 +81,7 @@ export function AdminInviteCodePage({
const payload: AdminUpsertProfileInviteCodeRequest = {
inviteCode: inviteCode.trim(),
metadata: parseMetadata(metadataText),
grantedUserTags: parseUserTags(grantedTagsText),
startsAt: startsAt ? toIsoDateTime(startsAt) : null,
expiresAt: expiresAt ? toIsoDateTime(expiresAt) : null,
};
@@ -115,6 +117,7 @@ export function AdminInviteCodePage({
setInviteCode(entry.inviteCode);
setStartsAt(toDateTimeLocalValue(entry.startsAt));
setExpiresAt(toDateTimeLocalValue(entry.expiresAt));
setGrantedTagsText(entry.grantedUserTags.join('、'));
setMetadataText(JSON.stringify(entry.metadata, null, 2));
}
@@ -174,6 +177,15 @@ export function AdminInviteCodePage({
</label>
</div>
<label className="admin-field">
<span></span>
<input
autoComplete="off"
value={grantedTagsText}
onChange={(event) => setGrantedTagsText(event.target.value)}
/>
</label>
<label className="admin-field">
<span>Metadata JSON</span>
<textarea
@@ -222,6 +234,7 @@ export function AdminInviteCodePage({
<thead>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
@@ -238,6 +251,9 @@ export function AdminInviteCodePage({
{entry.inviteCode}
</button>
</td>
<td>
<TagList tags={entry.grantedUserTags} />
</td>
<td>
<span className={`admin-status ${inviteValidityClass(entry)}`}>
{inviteValidityLabel(entry)}
@@ -272,6 +288,12 @@ export function AdminInviteCodePage({
<dt></dt>
<dd>{formatValidityWindow(result)}</dd>
</div>
<div>
<dt></dt>
<dd>
<TagList tags={result.grantedUserTags} />
</dd>
</div>
<div>
<dt></dt>
<dd>{result.createdAt}</dd>
@@ -300,6 +322,33 @@ export function AdminInviteCodePage({
);
}
function TagList({tags}: {tags: string[]}) {
if (!tags.length) {
return <span className="admin-muted-text">-</span>;
}
return (
<span className="admin-tag-list">
{tags.map((tag) => (
<span className="admin-tag" key={tag}>
{tag}
</span>
))}
</span>
);
}
function parseUserTags(value: string) {
const tags: string[] = [];
for (const raw of value.split(/[\n,;;、]+/)) {
const tag = raw.trim();
if (tag && !tags.includes(tag)) {
tags.push(tag);
}
}
return tags;
}
function parseMetadata(value: string): Record<string, unknown> {
const trimmed = value.trim();
if (!trimmed) {