Files
community-rule/lib/create/ruleInviteCardMeta.ts
T

75 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { parsePublishedDocumentForCommunityRuleDisplay } from "./publishedDocumentToDisplaySections";
import { formatInviteCountWord } from "./parseInviteEmails";
import { RULE_SECTION_CATEGORY } from "./ruleSectionsFromMethodSelections";
import sharedTerms from "../../messages/en/create/sharedTerms.json";
const DESCRIPTION_MAX = 140;
/** Initials for the invite email disc when the group has no photo. */
export function communityInviteInitials(name: string): string {
const words = name
.trim()
.split(/\s+/)
.filter((word) => word.length > 0);
if (words.length === 0) return "·";
if (words.length === 1) {
const word = words[0] ?? "";
return word.slice(0, 2).toUpperCase();
}
const first = words[0]?.charAt(0) ?? "";
const second = words[1]?.charAt(0) ?? "";
return `${first}${second}`.toUpperCase();
}
/** Possessive for footer copy (`Share’s` / `Members’`). */
export function communityPossessive(name: string): string {
const trimmed = name.trim();
if (trimmed.length === 0) return "this community’s";
if (/s$/i.test(trimmed)) return `${trimmed}’`;
return `${trimmed}’s`;
}
/** Community description on the invite card, cut at 140 characters. */
export function clipCommunityInviteDescription(
raw: string | null | undefined,
): string {
const trimmed = typeof raw === "string" ? raw.trim() : "";
if (trimmed.length <= DESCRIPTION_MAX) return trimmed;
return trimmed.slice(0, DESCRIPTION_MAX).trimEnd();
}
/** Values vs method cards on a published Rule. Shared terms do not count. */
export function inviteRuleValueAndCardCounts(document: unknown): {
values: number;
cards: number;
} {
const sections = parsePublishedDocumentForCommunityRuleDisplay(document);
let values = 0;
let cards = 0;
for (const section of sections) {
const n = section.entries.length;
if (section.categoryName === RULE_SECTION_CATEGORY.values) {
values += n;
} else if (section.categoryName !== sharedTerms.sectionTitle) {
cards += n;
}
}
return { values, cards };
}
/** Tag on the invite Rule card (`3 VALUES AND 6 CARDS`). Shared terms do not count. */
export function inviteRuleCountsLabel(document: unknown): string {
const { values, cards } = inviteRuleValueAndCardCounts(document);
const valuePart = values === 1 ? "1 VALUE" : `${values} VALUES`;
const cardPart = cards === 1 ? "1 CARD" : `${cards} CARDS`;
return `${valuePart} AND ${cardPart}`;
}
/** Spoken counts for Make a copy (`three values and six cards`). */
export function inviteRuleCountsSpoken(document: unknown): string {
const { values, cards } = inviteRuleValueAndCardCounts(document);
const valueNoun = values === 1 ? "value" : "values";
const cardNoun = cards === 1 ? "card" : "cards";
return `${formatInviteCountWord(values)} ${valueNoun} and ${formatInviteCountWord(cards)} ${cardNoun}`;
}