profileSets avatar / types fix (#794)
* profileSets avatar / types fix - Fix avatar pending payload flow to use USER_PROFILE_SETTINGS_SET_PENDING_AVATAR with NEW_ASSET imageUri payload. - Resolve TypeScript typing issues around IconUtils avatar/banner URL resolution without any casts. - Remove debug logging and legacy pending dispatch paths; keep recents and profile pending behavior aligned with current Discord profile settings. - Clean up profileSets rulebook compliance issues (nullish coalescing/defaults, typed preset field updates, no logger/console usage). * profilesets: remove display name sanitizer subscription * fixed checks * fix pending profile event flow * skip collectible dispatch when already equipped * fixed checks * Remove empty stop method from profile set plugin Removed the empty stop method from the profile set plugin. * bleh * Update src/equicordplugins/profileSets/utils/profile.ts Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update src/equicordplugins/profileSets/utils/profile.ts Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * t * fix fallback guard * restore avatar size fallback * fix fallback guard * fix fallback guard * fix to slider * address gemini review issues * fix avatarSize * update avatarSize * address review: destructure avatarSize * restore direct avatarSize access * destructure avatarSize * Apply suggestion from @gemini-code-assist[bot] Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Apply suggestion from @gemini-code-assist[bot] Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Apply suggestion from @gemini-code-assist[bot] Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --------- Co-authored-by: thororen <78185467+thororen1234@users.noreply.github.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
parent
cd125be7e8
commit
189ab429bb
7 changed files with 191 additions and 122 deletions
|
|
@ -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. */
|
||||
|
|
|
|||
2
packages/discord-types/src/common/User.d.ts
vendored
2
packages/discord-types/src/common/User.d.ts
vendored
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<ProfilePreset, "name" | "timestamp">;
|
||||
const [renaming, setRenaming] = React.useState<number>(-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();
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)'
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
|
|||
|
|
@ -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<string, unknown>;
|
||||
|
||||
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<ProfilePreset, "name" | "timestamp">, value: any, section: PresetSection, guildId?: string) {
|
||||
export async function updatePresetField<K extends keyof Omit<ProfilePreset, "name" | "timestamp">>(
|
||||
index: number,
|
||||
field: K,
|
||||
value: Omit<ProfilePreset, "name" | "timestamp">[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();
|
||||
|
|
|
|||
|
|
@ -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<string, unknown> & {
|
||||
selectedAvatarRaw?: ImageInput;
|
||||
presetAvatarRaw?: ImageInput;
|
||||
selectedAvatarProcessed?: ImageInput;
|
||||
presetAvatarProcessed?: ImageInput;
|
||||
pendingAvatar?: ImageInput;
|
||||
avatar?: ImageInput;
|
||||
pendingBanner?: ImageInput;
|
||||
|
|
@ -30,39 +34,23 @@ type PendingChanges = Record<string, unknown> & {
|
|||
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<string, unknown>) {
|
||||
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<string | null> {
|
|||
async function processImage(imageData: ImageInput, userId: string, type: "avatar" | "banner", guildId?: string, useGuildPath?: boolean): Promise<string | null> {
|
||||
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<Omit<ProfilePreset, "name" | "timestamp">> {
|
||||
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<string, unknown>) => {
|
||||
dispatch(type, isGuild ? { ...payload, guildId } : payload);
|
||||
};
|
||||
const setPending = (type: string, payload: Record<string, unknown>) => {
|
||||
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<string, unknown>) => {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue