Resolves #(issue number)

## Description:

continuation of https://github.com/openfrontio/infra/pull/359
adds ability to put discord URL into a dedicated slot 

pc:
<img width="1917" height="921" alt="image"
src="https://github.com/user-attachments/assets/100a25d5-e998-4744-904e-df40b74ccd76"
/>

mobile:
<img width="385" height="826" alt="image"
src="https://github.com/user-attachments/assets/de904f83-c88f-41e7-9c98-81c2296ec9a2"
/>


## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory

## Please put your Discord username so you can be contacted if a bug or
regression is found:

w.o.n

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ryan
2026-06-24 23:15:05 +01:00
committed by GitHub
parent 8ce5f3439c
commit 8ffb19d938
8 changed files with 534 additions and 30 deletions
+33
View File
@@ -36,12 +36,45 @@ export const ClanInfoSchema = z.object({
name: z.string().max(35),
tag: RequiredClanTagSchema,
description: z.string().max(200),
// Discord invite URL set by the clan leader; null when unset. Optional
// because not every ClanInfo source includes it (e.g. browse results).
discordUrl: z.string().max(255).nullable().optional(),
isOpen: z.boolean(),
createdAt: z.iso.datetime().optional(),
memberCount: z.number().optional(),
});
export type ClanInfo = z.infer<typeof ClanInfoSchema>;
// Client-assembled view model for the clan Discord card. `valid` is false only
// on a definitive Discord 404 (invite revoked); other failures degrade to the
// plain link with valid: true.
export type ClanDiscord = {
url: string;
valid: boolean;
serverName?: string;
iconUrl?: string | null;
bannerUrl?: string | null;
description?: string | null;
onlineCount?: number | null;
memberCount?: number | null;
};
// Subset of Discord's public GET /invites/{code}?with_counts=true response,
// parsed client-side into ClanDiscord. snake_case mirrors Discord's wire format.
export const DiscordInviteResponseSchema = z.object({
guild: z
.object({
id: z.string(),
name: z.string(),
icon: z.string().nullable().optional(),
banner: z.string().nullable().optional(),
description: z.string().nullable().optional(),
})
.optional(),
approximate_member_count: z.number().optional(),
approximate_presence_count: z.number().optional(),
});
export const ClanBrowseResponseSchema = z.object({
results: ClanInfoSchema.array(),
total: z.number(),