admin: gift granting, collectible attribute/number control, and Layer 228 moderation tools
Admin console additions (Layer 228): - Give Gifts: dedicated tab with sorted Lottie/TGS gift picker + inline form; grant any catalog gift to a user/channel from 777000 (no charge) - Upgraded/collectible delivery: mint a unique gift with admin-selected model/pattern/backdrop and custom number, or random/auto (DB FK + UNIQUE(gift_id,num) enforce invariants) - SCAM/FAKE flags for users/channels (migration 0136) with configurable profile warning (TELESRV_SCAM_WARNING/TELESRV_FAKE_WARNING) - Support toggle, force channel settings incl. gigagroup (migration 0137), username management, cosmetic color/emoji-status - Emoji admin tab (custom emoji list + document IDs + Lottie/TGS preview) - Bot management; soft UI / dark theme Wired through Router -> admin.Service -> adminapi -> BFF -> React panel (en/zh/ru).
This commit is contained in:
parent
9e45da69ef
commit
313624eab2
63 changed files with 3650 additions and 71 deletions
59
cmd/telesrv-admin/web/src/components/flags.tsx
Normal file
59
cmd/telesrv-admin/web/src/components/flags.tsx
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import { ShieldAlert, ShieldX } from "lucide-react";
|
||||
import { useI18n } from "../i18n";
|
||||
import { ActionButton } from "./ActionButton";
|
||||
import { Badge } from "./ui";
|
||||
|
||||
// ScamFakeBadges renders the SCAM/FAKE moderation labels when set.
|
||||
export function ScamFakeBadges({ scam, fake }: { scam: boolean; fake: boolean }) {
|
||||
const { t } = useI18n();
|
||||
if (!scam && !fake) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{scam && <Badge tone="danger">{t("flags.scam")}</Badge>}
|
||||
{fake && <Badge tone="danger">{t("flags.fake")}</Badge>}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// ScamFakeActions renders the two independent toggles. The combined setter
|
||||
// receives the full desired state, so each button flips one flag and keeps the
|
||||
// other unchanged.
|
||||
export function ScamFakeActions({
|
||||
idKey,
|
||||
id,
|
||||
path,
|
||||
scam,
|
||||
fake,
|
||||
onDone
|
||||
}: {
|
||||
idKey: "user_id" | "channel_id";
|
||||
id: number;
|
||||
path: string;
|
||||
scam: boolean;
|
||||
fake: boolean;
|
||||
onDone: () => void;
|
||||
}) {
|
||||
const { t } = useI18n();
|
||||
return (
|
||||
<div className="action-stack">
|
||||
<ActionButton
|
||||
label={scam ? t("flags.clearScam") : t("flags.setScam")}
|
||||
icon={<ShieldAlert size={15} />}
|
||||
tone="danger"
|
||||
path={path}
|
||||
payload={() => ({ [idKey]: id, scam: !scam, fake })}
|
||||
onDone={onDone}
|
||||
/>
|
||||
<ActionButton
|
||||
label={fake ? t("flags.clearFake") : t("flags.setFake")}
|
||||
icon={<ShieldX size={15} />}
|
||||
tone="danger"
|
||||
path={path}
|
||||
payload={() => ({ [idKey]: id, scam, fake: !fake })}
|
||||
onDone={onDone}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue