diff --git a/packages/discord-types/src/common/Channel.d.ts b/packages/discord-types/src/common/Channel.d.ts index 6ae5ba895..21f2dc10e 100644 --- a/packages/discord-types/src/common/Channel.d.ts +++ b/packages/discord-types/src/common/Channel.d.ts @@ -14,15 +14,15 @@ export interface PermissionOverwrite { export interface AvatarDecorationData { asset: string; expires_at: string | null; - sku_id: string; + skuId: string; } /** Clan identity information. */ export interface ClanData { badge: string; - identity_enabled: boolean; - identity_guild_id: string; tag: string; + identityEnabled: boolean; + identityGuildId: string; } /** Display name style configuration. */ @@ -38,7 +38,8 @@ export interface CollectibleItem { expires_at: string | null; label: string; palette: string; - sku_id: string; + type: number; + skuId: string; } /** User collectibles configuration. */ diff --git a/packages/discord-types/src/common/User.d.ts b/packages/discord-types/src/common/User.d.ts index 0905b8bf2..f3007f120 100644 --- a/packages/discord-types/src/common/User.d.ts +++ b/packages/discord-types/src/common/User.d.ts @@ -39,7 +39,7 @@ export class User extends DiscordRecord { get avatarDecoration(): AvatarDecorationData | null; get createdAt(): Date; get isProvisional(): boolean; - get nameplate(): { asset: string; sku_id: string; } | null; + get nameplate(): { asset: string; skuId: string; } | null; get premiumGroupRole(): { id: string; name: string; color: number; } | null; get tag(): string; diff --git a/src/equicordplugins/profileSets/components/presetList.tsx b/src/equicordplugins/profileSets/components/presetList.tsx index 2beb5bc9e..61bf18ce6 100644 --- a/src/equicordplugins/profileSets/components/presetList.tsx +++ b/src/equicordplugins/profileSets/components/presetList.tsx @@ -4,7 +4,9 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +import { isNonNullish } from "@utils/guards"; import { classes } from "@utils/misc"; +import { ProfilePreset } from "@vencord/discord-types"; import { ContextMenuApi, Menu, React, TextInput } from "@webpack/common"; import { cl } from ".."; @@ -37,6 +39,7 @@ export function PresetList({ currentPage, onPageChange }: PresetListProps) { + type EditableProfile = Omit; const [renaming, setRenaming] = React.useState(-1); const [renameText, setRenameText] = React.useState(""); const isGuildProfile = section === "server"; @@ -149,11 +152,11 @@ export function PresetList({ label="Update" action={async () => { const profile = await getCurrentProfile(guildId, { isGuildProfile }); - Object.entries(profile).forEach(([key, value]) => { - if (value !== null && value !== undefined) { - updatePresetField(actualIndex, key as any, value, section, guildId); - } - }); + await Promise.all( + (Object.entries(profile) as [keyof EditableProfile, EditableProfile[keyof EditableProfile]][]) + .filter(([, value]) => isNonNullish(value)) + .map(([key, value]) => updatePresetField(actualIndex, key, value, section, guildId)) + ); onUpdate(); }} /> diff --git a/src/equicordplugins/profileSets/components/presetManager.tsx b/src/equicordplugins/profileSets/components/presetManager.tsx index b50090720..74f2c5bc8 100644 --- a/src/equicordplugins/profileSets/components/presetManager.tsx +++ b/src/equicordplugins/profileSets/components/presetManager.tsx @@ -137,7 +137,7 @@ export function PresetManager({ section, guildId }: PresetManagerProps) { }); }; - const avatarSize = settings.store.avatarSize || 40; + const { avatarSize } = settings.store; const hasPresets = presets.length > 0; const shouldShowPagination = filteredPresets.length > PRESETS_PER_PAGE; diff --git a/src/equicordplugins/profileSets/index.tsx b/src/equicordplugins/profileSets/index.tsx index dccb74a8c..a2db97aa4 100644 --- a/src/equicordplugins/profileSets/index.tsx +++ b/src/equicordplugins/profileSets/index.tsx @@ -18,9 +18,11 @@ import { loadPresets, PresetSection } from "./utils/storage"; export const cl = classNameFactory("vc-profile-presets-"); export const settings = definePluginSettings({ avatarSize: { - type: OptionType.NUMBER, + type: OptionType.SLIDER, description: "Avatar size in preset list.", - default: 40, + markers: [56, 64, 72, 80, 88, 96], + default: 56, + stickToMarkers: true }, }); @@ -40,8 +42,8 @@ export default definePlugin({ { find: "USER_SETTINGS_GUILD_PROFILE)", replacement: { - match: /onChange:\i\}\)(?=.{0,25}profilePreviewTitle:)/, - replace: '$&,$self.renderPresetSection("server")' + match: /guildId:(\i\.id),onChange:(\i)\}\)(?=.{0,25}profilePreviewTitle:)/, + replace: 'guildId:$1,onChange:$2}),$self.renderPresetSection("server",$1)' } } ], diff --git a/src/equicordplugins/profileSets/utils/actions.ts b/src/equicordplugins/profileSets/utils/actions.ts index eef4b916d..a43aa3e24 100644 --- a/src/equicordplugins/profileSets/utils/actions.ts +++ b/src/equicordplugins/profileSets/utils/actions.ts @@ -4,24 +4,64 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +import { isNonNullish } from "@utils/guards"; import { ProfilePreset } from "@vencord/discord-types"; +import { findStoreLazy } from "@webpack"; +import { showToast, Toasts } from "@webpack/common"; import { getCurrentProfile } from "./profile"; -import { addPreset, movePresetInArray, PresetSection, presets, removePreset, replaceAllPresets, savePresetsData, updatePreset, type ProfilePresetEx } from "./storage"; +import { addPreset, movePresetInArray, presets, PresetSection, type ProfilePresetEx, removePreset, replaceAllPresets, savePresetsData, updatePreset } from "./storage"; + +const UserProfileSettingsStore = findStoreLazy("UserProfileSettingsStore"); + +function isImageInput(value: unknown): value is string | { imageUri: string; } { + if (typeof value === "string") return value.length > 0; + return typeof value === "object" && isNonNullish(value) && "imageUri" in value && typeof (value as { imageUri: unknown }).imageUri === "string"; +} + +function getFreshPendingAvatar(section: PresetSection, guildId?: string): string | null { + const pending = (section === "server" && guildId + ? UserProfileSettingsStore.getPendingChanges?.(guildId) + : UserProfileSettingsStore.getPendingChanges?.()) ?? {}; + const pendingObj = pending as Record; + + const candidates = [ + pendingObj.selectedAvatarRaw, + pendingObj.presetAvatarRaw, + pendingObj.pendingAvatar, + pendingObj.avatar, + pendingObj.selectedAvatarProcessed, + pendingObj.presetAvatarProcessed + ]; + const selected = candidates.find(isImageInput); + if (!selected) return null; + return typeof selected === "string" ? selected : selected.imageUri; +} export async function savePreset(name: string, section: PresetSection, guildId?: string) { const profile = await getCurrentProfile(guildId, { isGuildProfile: section === "server" }); + const freshPendingAvatar = getFreshPendingAvatar(section, guildId); + const effectiveAvatar = freshPendingAvatar ?? profile.avatarDataUrl ?? null; + const newPreset: ProfilePresetEx = { name, timestamp: Date.now(), ...profile, + avatarDataUrl: effectiveAvatar, }; addPreset(newPreset); await savePresetsData(section); } -export async function updatePresetField(index: number, field: keyof Omit, value: any, section: PresetSection, guildId?: string) { +export async function updatePresetField>( + index: number, + field: K, + value: Omit[K], + section: PresetSection, + guildId?: string +) { if (index < 0 || index >= presets.length) return; + void guildId; const updatedPreset = { ...presets[index], @@ -55,17 +95,14 @@ export async function renamePreset(index: number, newName: string, section: Pres } export function exportPresets(section: PresetSection) { - try { - const dataStr = JSON.stringify(presets, null, 2); - const dataBlob = new Blob([dataStr], { type: "application/json" }); - const url = URL.createObjectURL(dataBlob); - const link = document.createElement("a"); - link.href = url; - link.download = `profile-presets-${section}-${Date.now()}.json`; - link.click(); - URL.revokeObjectURL(url); - } catch { - } + const dataStr = JSON.stringify(presets, null, 2); + const dataBlob = new Blob([dataStr], { type: "application/json" }); + const url = URL.createObjectURL(dataBlob); + const link = document.createElement("a"); + link.href = url; + link.download = `profile-presets-${section}-${Date.now()}.json`; + link.click(); + URL.revokeObjectURL(url); } export type ImportDecision = "override" | "merge" | "cancel"; @@ -108,6 +145,7 @@ export async function importPresets( await savePresetsData(section); forceUpdate(); } catch { + showToast("Failed to import presets. The file might be invalid.", Toasts.Type.FAILURE); } }; input.click(); diff --git a/src/equicordplugins/profileSets/utils/profile.ts b/src/equicordplugins/profileSets/utils/profile.ts index 69d4dcd84..5b7a7bbc7 100644 --- a/src/equicordplugins/profileSets/utils/profile.ts +++ b/src/equicordplugins/profileSets/utils/profile.ts @@ -7,12 +7,16 @@ import { getUserSettingLazy } from "@api/UserSettings"; import { CustomStatus, DisplayNameStyles, Nameplate, ProfileEffect, ProfilePreset } from "@vencord/discord-types"; import { findStoreLazy } from "@webpack"; -import { FluxDispatcher, GuildMemberStore,IconUtils, UserProfileStore, UserStore } from "@webpack/common"; +import { FluxDispatcher, GuildMemberStore, IconUtils, UserProfileStore, UserStore } from "@webpack/common"; const UserProfileSettingsStore = findStoreLazy("UserProfileSettingsStore"); const CustomStatusSettings = getUserSettingLazy("status", "customStatus")!; type PendingChanges = Record & { + selectedAvatarRaw?: ImageInput; + presetAvatarRaw?: ImageInput; + selectedAvatarProcessed?: ImageInput; + presetAvatarProcessed?: ImageInput; pendingAvatar?: ImageInput; avatar?: ImageInput; pendingBanner?: ImageInput; @@ -30,39 +34,23 @@ type PendingChanges = Record & { pendingPrimaryGuildId?: string | null; }; -type UserExtras = { - collectibles?: { - nameplate?: Nameplate; - }; - displayNameStyles?: DisplayNameStyles; - avatarDecorationData?: { - asset: string; - skuId: string; - } | null; - primaryGuild?: { - identityGuildId?: string | null; - } | null; -}; - -type ProfileCollectible = { - skuId: string; - title?: string; - description?: string; - accessibilityLabel?: string; - reducedMotionSrc?: string; - thumbnailPreviewSrc?: string; - effects?: ProfileEffect["effects"]; - animationType?: number; - staticFrameSrc?: string; - type?: number; -}; - type ImageInput = string | { imageUri: string; } | null | undefined; type DisplayNameStylesLike = DisplayNameStyles & { fontId?: number; effectId?: number; }; +type CurrentProfileOptions = { + isGuildProfile?: boolean; +}; + +type LoadPresetOptions = { + skipGlobalName?: boolean; + skipBio?: boolean; + skipPronouns?: boolean; + isGuildProfile?: boolean; +}; + function dispatch(type: string, payload: Record) { FluxDispatcher.dispatch({ type, ...payload }); } @@ -74,7 +62,7 @@ function isNonEmptyString(value: unknown): value is string { function hasImageInput(value: ImageInput): boolean { if (!value) return false; if (typeof value === "string") return value.length > 0; - return typeof value === "object" && "imageUri" in value && isNonEmptyString(value.imageUri); + return typeof value === "object" && isNonEmptyString(value?.imageUri); } function normalizeDisplayNameStyles(value: DisplayNameStylesLike | null | undefined): DisplayNameStylesLike | null { @@ -111,7 +99,7 @@ export async function imageUrlToBase64(url: string): Promise { async function processImage(imageData: ImageInput, userId: string, type: "avatar" | "banner", guildId?: string, useGuildPath?: boolean): Promise { if (!imageData) return null; - if (typeof imageData === "object" && "imageUri" in imageData && isNonEmptyString(imageData.imageUri)) { + if (typeof imageData === "object" && isNonEmptyString(imageData?.imageUri)) { return imageData.imageUri; } @@ -137,17 +125,6 @@ async function processImage(imageData: ImageInput, userId: string, type: "avatar return null; } -type CurrentProfileOptions = { - isGuildProfile?: boolean; -}; - -type LoadPresetOptions = { - skipGlobalName?: boolean; - skipBio?: boolean; - skipPronouns?: boolean; - isGuildProfile?: boolean; -}; - export async function getCurrentProfile(guildId?: string, options: CurrentProfileOptions = {}): Promise> { const currentUser = UserStore.getCurrentUser(); const baseProfile = UserProfileStore.getUserProfile(currentUser.id); @@ -155,19 +132,17 @@ export async function getCurrentProfile(guildId?: string, options: CurrentProfil const effectiveGuildId = isGuildProfile ? guildId : undefined; const guildProfile = effectiveGuildId ? UserProfileStore.getGuildMemberProfile(currentUser.id, effectiveGuildId) : null; const userProfile = guildProfile ?? baseProfile; - const userAny = currentUser as UserExtras; + const userAny = currentUser; const guildMember = effectiveGuildId ? GuildMemberStore.getMember(effectiveGuildId, currentUser.id) : null; - const pendingChangesDefault = (UserProfileSettingsStore.getPendingChanges() ?? {}) as PendingChanges; - const pendingChangesForGuild = (effectiveGuildId - ? (UserProfileSettingsStore.getPendingChanges(effectiveGuildId) ?? {}) - : {}) as PendingChanges; + const pendingChangesDefault: PendingChanges = UserProfileSettingsStore.getPendingChanges() ?? {}; + const pendingChangesForGuild: PendingChanges = UserProfileSettingsStore.getPendingChanges(effectiveGuildId) ?? {}; const pendingChanges: PendingChanges = isGuildProfile && Object.keys(pendingChangesForGuild).length > 0 ? pendingChangesForGuild : pendingChangesDefault; const customStatusSetting = CustomStatusSettings.getSetting(); - const customStatus: CustomStatus | null = isGuildProfile + const customStatus = isGuildProfile ? null : { text: customStatusSetting?.text ?? "", @@ -200,7 +175,7 @@ export async function getCurrentProfile(guildId?: string, options: CurrentProfil type: effectToUse.type || 1 }; } else if (effectToUse.skuId) { - const collectibles = (userProfile as { collectibles?: ProfileCollectible[]; } | null)?.collectibles; + const collectibles = userProfile?.collectibles; const collectible = collectibles?.find(c => c?.skuId === effectToUse.skuId); if (collectible) { profileEffect = { @@ -232,7 +207,7 @@ export async function getCurrentProfile(guildId?: string, options: CurrentProfil ? (guildMember?.displayNameStyles ?? userAny.displayNameStyles) : userAny.displayNameStyles; const displayNameStylesToUse = pendingChanges.pendingDisplayNameStyles ?? savedDisplayNameStyles; - const displayNameStyles = normalizeDisplayNameStyles(displayNameStylesToUse as DisplayNameStylesLike | null | undefined); + const displayNameStyles = normalizeDisplayNameStyles(displayNameStylesToUse); const pendingAvatar = pendingChanges.pendingAvatar ?? pendingChanges.avatar; const avatarToUse: ImageInput = hasImageInput(pendingAvatar) @@ -282,109 +257,159 @@ function jsonEq(a: unknown, b: unknown): boolean { } function customStatusEq(a: CustomStatus | null | undefined, b: CustomStatus | null | undefined): boolean { - if (a == null && b == null) return true; - if (a == null || b == null) return false; + if (a == null || b == null) return a == null && b == null; return a.text === b.text && String(a.emojiId ?? "") === String(b.emojiId ?? "") && a.emojiName === b.emojiName && String(a.expiresAtMs ?? "0") === String(b.expiresAtMs ?? "0"); } +function resolvePendingAvatar(pendingChanges: PendingChanges | null): ImageInput { + if (!pendingChanges) return null; + + const candidates: ImageInput[] = [ + pendingChanges.selectedAvatarRaw, + pendingChanges.presetAvatarRaw, + pendingChanges.pendingAvatar, + pendingChanges.avatar, + pendingChanges.selectedAvatarProcessed, + pendingChanges.presetAvatarProcessed + ]; + return candidates.find(hasImageInput) ?? null; +} + +function normalizeImageValue(value: unknown): string | null { + if (typeof value === "string") return value; + if (value && typeof value === "object" && "imageUri" in value) { + const { imageUri } = value as { imageUri: unknown }; + return typeof imageUri === "string" ? imageUri : null; + } + return null; +} + +function collectibleEqBySku(a: { skuId?: string | number | null; } | null | undefined, b: { skuId?: string | number | null; } | null | undefined): boolean { + if (a == null || b == null) return a == null && b == null; + return String(a.skuId ?? "") === String(b.skuId ?? ""); +} + +function avatarDecorationEq(a: { skuId?: string | number | null; asset?: string | null; } | null | undefined, b: { skuId?: string | number | null; asset?: string | null; } | null | undefined): boolean { + if (a == null || b == null) return a == null && b == null; + return String(a.skuId ?? "") === String(b.skuId ?? "") && String(a.asset ?? "") === String(b.asset ?? ""); +} + +function nameplateEq(a: { skuId?: string | number | null; asset?: string | null; } | null | undefined, b: { skuId?: string | number | null; asset?: string | null; } | null | undefined): boolean { + if (a == null || b == null) return a == null && b == null; + return String(a.skuId ?? "") === String(b.skuId ?? "") && String(a.asset ?? "") === String(b.asset ?? ""); +} + export async function loadPresetAsPending(preset: ProfilePreset, guildId?: string, options: LoadPresetOptions = {}) { try { const isGuild = options.isGuildProfile ?? Boolean(guildId); if (isGuild && !guildId) return; + const currentUser = UserStore.getCurrentUser(); + const baseProfile = UserProfileStore.getUserProfile(currentUser.id); + const guildProfile = isGuild && guildId ? UserProfileStore.getGuildMemberProfile(currentUser.id, guildId) : null; + const equippedProfile = guildProfile ?? baseProfile; const current = await getCurrentProfile(guildId, { isGuildProfile: isGuild }); - const profilePrefix = isGuild ? "GUILD_IDENTITY_SETTINGS" : "USER_SETTINGS_ACCOUNT"; - const dispatchProfile = (type: string, payload: Record) => { - dispatch(type, isGuild ? { ...payload, guildId } : payload); - }; - const setPending = (type: string, payload: Record) => { - dispatchProfile(type, payload); - if (isGuild && type.startsWith("GUILD_IDENTITY_SETTINGS_")) { - dispatchProfile(type.replace("GUILD_IDENTITY_SETTINGS_", "USER_SETTINGS_ACCOUNT_"), payload); - } + const pendingChanges = (isGuild && guildId + ? UserProfileSettingsStore.getPendingChanges(guildId) + : UserProfileSettingsStore.getPendingChanges()); + const equippedAvatarDecoration = currentUser.avatarDecorationData ?? null; + const equippedProfileEffect = equippedProfile?.profileEffect ?? null; + const equippedNameplate = currentUser.collectibles?.nameplate ?? null; + const pendingAvatarDecoration = pendingChanges?.pendingAvatarDecoration ?? null; + const pendingProfileEffect = pendingChanges?.pendingProfileEffect ?? null; + const pendingNameplate = pendingChanges?.pendingNameplate ?? null; + const setPending = (field: string, payload: Record) => { + const cleanPayload = Object.fromEntries(Object.entries(payload).filter(([, v]) => v !== undefined)); + if (!Object.keys(cleanPayload).length) return; + dispatch(`USER_PROFILE_SETTINGS_SET_PENDING_${field}`, isGuild ? { ...cleanPayload, guildId } : cleanPayload); }; if ("avatarDataUrl" in preset) { const avatarValue = preset.avatarDataUrl; - if (isGuild || avatarValue !== current.avatarDataUrl) { - setPending(`${profilePrefix}_SET_PENDING_AVATAR`, { avatar: avatarValue }); + const presetAvatar = normalizeImageValue(avatarValue); + const currentAvatar = normalizeImageValue(current.avatarDataUrl); + const pendingAvatar = normalizeImageValue(resolvePendingAvatar(pendingChanges)); + if (isGuild || (presetAvatar !== currentAvatar && presetAvatar !== pendingAvatar)) { + const avatarPayload = + typeof avatarValue === "string" && avatarValue.startsWith("data:") + ? { + assetOrigin: "NEW_ASSET", + imageUri: avatarValue, + description: `profilesets-${preset.name ?? "preset"}` + } + : avatarValue; + setPending("AVATAR", { avatar: avatarPayload }); } } if ("bannerDataUrl" in preset && preset.bannerDataUrl !== current.bannerDataUrl) { - setPending(`${profilePrefix}_SET_PENDING_BANNER`, { banner: preset.bannerDataUrl }); + setPending("BANNER", { banner: preset.bannerDataUrl }); } - if (!options.skipBio && "bio" in preset && preset.bio !== current.bio) { + if (!options.skipBio && preset?.bio !== current?.bio) { const bioValue = preset.bio === null ? "" : preset.bio; - setPending(`${profilePrefix}_SET_PENDING_BIO`, { bio: bioValue }); + setPending("BIO", { bio: bioValue }); } - if (!isGuild && !options.skipPronouns && "pronouns" in preset && preset.pronouns !== current.pronouns) { + if (!isGuild && !options.skipPronouns && preset?.pronouns !== current?.pronouns) { const pronounsValue = preset.pronouns === null ? "" : preset.pronouns; - setPending(`${profilePrefix}_SET_PENDING_PRONOUNS`, { pronouns: pronounsValue }); + setPending("PRONOUNS", { pronouns: pronounsValue }); } - if (!options.skipGlobalName && preset.globalName !== undefined && preset.globalName !== current.globalName) { + if (!options.skipGlobalName && preset?.globalName !== current?.globalName) { if (isGuild) { - setPending("GUILD_IDENTITY_SETTINGS_SET_PENDING_NICKNAME", { nickname: preset.globalName }); + setPending("NICKNAME", { nickname: preset.globalName }); } else { - setPending("USER_SETTINGS_ACCOUNT_SET_PENDING_GLOBAL_NAME", { globalName: preset.globalName }); + setPending("GLOBAL_NAME", { globalName: preset.globalName }); } } - if (preset.avatarDecoration !== undefined && !jsonEq(preset.avatarDecoration, current.avatarDecoration)) { - dispatchProfile(`${profilePrefix}_SET_PENDING_COLLECTIBLES_ITEM`, { + if (preset.avatarDecoration && ![pendingAvatarDecoration, equippedAvatarDecoration, current.avatarDecoration].some(d => avatarDecorationEq(preset.avatarDecoration, d))) { + setPending("COLLECTIBLES_ITEM", { item: { type: 0, value: preset.avatarDecoration } }); } - if (preset.profileEffect !== undefined && !jsonEq(preset.profileEffect, current.profileEffect)) { - dispatchProfile(`${profilePrefix}_SET_PENDING_COLLECTIBLES_ITEM`, { + if (preset.profileEffect && ![pendingProfileEffect, equippedProfileEffect, current.profileEffect].some(d => collectibleEqBySku(preset.profileEffect, d))) { + setPending("COLLECTIBLES_ITEM", { item: { type: 1, value: preset.profileEffect } }); } - if (preset.nameplate !== undefined && !jsonEq(preset.nameplate, current.nameplate)) { - dispatchProfile(`${profilePrefix}_SET_PENDING_COLLECTIBLES_ITEM`, { + if (preset.nameplate && ![pendingNameplate, equippedNameplate, current.nameplate].some(d => nameplateEq(preset.nameplate, d))) { + setPending("COLLECTIBLES_ITEM", { item: { type: 2, value: preset.nameplate } }); } - if (preset.displayNameStyles !== undefined) { - const presetDisplayNameStyles = normalizeDisplayNameStyles(preset.displayNameStyles as DisplayNameStylesLike | null | undefined); + if (preset.displayNameStyles) { + const presetDisplayNameStyles = normalizeDisplayNameStyles(preset.displayNameStyles); if (!jsonEq(presetDisplayNameStyles, current.displayNameStyles)) { - setPending(`${profilePrefix}_SET_PENDING_DISPLAY_NAME_STYLES`, { displayNameStyles: presetDisplayNameStyles }); + setPending("DISPLAY_NAME_STYLES", { displayNameStyles: presetDisplayNameStyles }); } } - if (preset.themeColors !== undefined && !jsonEq(preset.themeColors, current.themeColors)) { - setPending(`${profilePrefix}_SET_PENDING_THEME_COLORS`, { themeColors: preset.themeColors }); + if (preset.themeColors && !jsonEq(preset.themeColors, current.themeColors)) { + setPending("THEME_COLORS", { themeColors: preset.themeColors }); } - if (preset.primaryGuildId !== undefined && !isGuild && preset.primaryGuildId !== current.primaryGuildId) { + if (preset.primaryGuildId && !isGuild && preset.primaryGuildId !== current.primaryGuildId) { dispatch("USER_SETTINGS_SET_PENDING_PRIMARY_GUILD_ID", { primaryGuildId: preset.primaryGuildId }); } - if (preset.customStatus !== undefined && !isGuild && !customStatusEq(preset.customStatus, current.customStatus)) { - const customStatusValue = preset.customStatus ?? { - text: "", - expiresAtMs: "0", - emojiId: "0", - emojiName: "" - }; + if (preset.customStatus && !isGuild && !customStatusEq(preset.customStatus, current.customStatus)) { CustomStatusSettings.updateSetting({ - text: customStatusValue.text || "", - expiresAtMs: customStatusValue.expiresAtMs || "0", - emojiId: customStatusValue.emojiId || "0", - emojiName: customStatusValue.emojiName || "" + text: preset.customStatus?.text ?? "", + expiresAtMs: preset.customStatus?.expiresAtMs ?? "0", + emojiId: preset.customStatus?.emojiId ?? "0", + emojiName: preset.customStatus?.emojiName ?? "" }); } } catch (err) { throw err; } -} \ No newline at end of file +}