mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz>
112 lines
3.0 KiB
TypeScript
112 lines
3.0 KiB
TypeScript
import { setLocalStorageItemWithRecovery } from "@/shared/lib/localStorageQuota";
|
|
|
|
const COMMUNITY_DESTINATIONS_KEY = "buzz-community-destinations";
|
|
let pendingCommunityRestoreId: string | null = null;
|
|
|
|
export type CommunityDestination =
|
|
| { kind: "home" }
|
|
| { kind: "channel"; channelId: string };
|
|
|
|
type CommunityDestinations = Record<string, CommunityDestination>;
|
|
|
|
function isCommunityDestination(value: unknown): value is CommunityDestination {
|
|
if (!value || typeof value !== "object") {
|
|
return false;
|
|
}
|
|
|
|
const candidate = value as Record<string, unknown>;
|
|
return (
|
|
candidate.kind === "home" ||
|
|
(candidate.kind === "channel" &&
|
|
typeof candidate.channelId === "string" &&
|
|
candidate.channelId.length > 0)
|
|
);
|
|
}
|
|
|
|
function loadCommunityDestinations(storage: Storage): CommunityDestinations {
|
|
try {
|
|
const raw = storage.getItem(COMMUNITY_DESTINATIONS_KEY);
|
|
if (!raw) {
|
|
return {};
|
|
}
|
|
|
|
const parsed: unknown = JSON.parse(raw);
|
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
return {};
|
|
}
|
|
|
|
return Object.fromEntries(
|
|
Object.entries(parsed).filter(
|
|
(entry): entry is [string, CommunityDestination] =>
|
|
isCommunityDestination(entry[1]),
|
|
),
|
|
);
|
|
} catch {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
function saveCommunityDestinations(
|
|
destinations: CommunityDestinations,
|
|
storage: Storage,
|
|
): void {
|
|
const serialized = JSON.stringify(destinations);
|
|
if (typeof window !== "undefined" && storage === window.localStorage) {
|
|
setLocalStorageItemWithRecovery(COMMUNITY_DESTINATIONS_KEY, serialized);
|
|
return;
|
|
}
|
|
storage.setItem(COMMUNITY_DESTINATIONS_KEY, serialized);
|
|
}
|
|
|
|
export function loadCommunityDestination(
|
|
communityId: string,
|
|
storage: Storage = localStorage,
|
|
): CommunityDestination | null {
|
|
return loadCommunityDestinations(storage)[communityId] ?? null;
|
|
}
|
|
|
|
export function saveCommunityDestination(
|
|
communityId: string,
|
|
destination: CommunityDestination,
|
|
storage: Storage = localStorage,
|
|
): void {
|
|
saveCommunityDestinations(
|
|
{ ...loadCommunityDestinations(storage), [communityId]: destination },
|
|
storage,
|
|
);
|
|
}
|
|
|
|
export function removeCommunityDestination(
|
|
communityId: string,
|
|
storage: Storage = localStorage,
|
|
): void {
|
|
if (pendingCommunityRestoreId === communityId) {
|
|
pendingCommunityRestoreId = null;
|
|
}
|
|
const destinations = loadCommunityDestinations(storage);
|
|
if (!(communityId in destinations)) {
|
|
return;
|
|
}
|
|
delete destinations[communityId];
|
|
saveCommunityDestinations(destinations, storage);
|
|
}
|
|
|
|
export function clearCommunityDestinations(
|
|
storage: Storage = localStorage,
|
|
): void {
|
|
storage.removeItem(COMMUNITY_DESTINATIONS_KEY);
|
|
pendingCommunityRestoreId = null;
|
|
}
|
|
|
|
export function markPendingCommunityRestore(communityId: string): void {
|
|
pendingCommunityRestoreId = communityId;
|
|
}
|
|
|
|
export function consumePendingCommunityRestore(communityId: string): boolean {
|
|
if (pendingCommunityRestoreId !== communityId) {
|
|
return false;
|
|
}
|
|
pendingCommunityRestoreId = null;
|
|
return true;
|
|
}
|