mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 21:15:32 +09:00
fix(guild): show duplicated role in its final spot without flicker (#2109)
This commit is contained in:
1 parent
470e752fba
commit
82043ce2a8
2 files changed
+34
-12
No files matched your search
@@ -254,9 +254,16 @@ export async function updateVanityURL(guildId: string, code: string | null): Pro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createRole(guildId: string, name: string): Promise<GuildRole> {
|
export async function createRole(
|
||||||
|
guildId: string,
|
||||||
|
name: string,
|
||||||
|
options?: {color?: number; permissions?: bigint},
|
||||||
|
): Promise<GuildRole> {
|
||||||
try {
|
try {
|
||||||
const response = await http.post<GuildRole>(Endpoints.GUILD_ROLES(guildId), {body: {name}});
|
const body: {name: string; color?: number; permissions?: string} = {name};
|
||||||
|
if (options?.color !== undefined) body.color = options.color;
|
||||||
|
if (options?.permissions !== undefined) body.permissions = options.permissions.toString();
|
||||||
|
const response = await http.post<GuildRole>(Endpoints.GUILD_ROLES(guildId), {body});
|
||||||
logger.debug(`Created role "${name}" in guild ${guildId}`);
|
logger.debug(`Created role "${name}" in guild ${guildId}`);
|
||||||
return response.body;
|
return response.body;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ const GuildRolesTab: React.FC<{guildId: string}> = observer(({guildId}) => {
|
|||||||
const [mobileShowEditor, setMobileShowEditor] = useState(false);
|
const [mobileShowEditor, setMobileShowEditor] = useState(false);
|
||||||
const [roleUpdates, setRoleUpdates] = useState<Map<string, RoleUpdate>>(new Map());
|
const [roleUpdates, setRoleUpdates] = useState<Map<string, RoleUpdate>>(new Map());
|
||||||
const [pendingRoleOrder, setPendingRoleOrder] = useState<Array<string> | null>(null);
|
const [pendingRoleOrder, setPendingRoleOrder] = useState<Array<string> | null>(null);
|
||||||
|
const [optimisticRoleOrder, setOptimisticRoleOrder] = useState<Array<string> | null>(null);
|
||||||
const [hoistOrderMode, setHoistOrderMode] = useState(false);
|
const [hoistOrderMode, setHoistOrderMode] = useState(false);
|
||||||
const [pendingHoistOrder, setPendingHoistOrder] = useState<Array<string> | null>(null);
|
const [pendingHoistOrder, setPendingHoistOrder] = useState<Array<string> | null>(null);
|
||||||
const [permissionSearchQuery, setPermissionSearchQuery] = useState('');
|
const [permissionSearchQuery, setPermissionSearchQuery] = useState('');
|
||||||
@@ -105,13 +106,16 @@ const GuildRolesTab: React.FC<{guildId: string}> = observer(({guildId}) => {
|
|||||||
if (!guild) return [];
|
if (!guild) return [];
|
||||||
const rolesList = Object.values(guild.roles);
|
const rolesList = Object.values(guild.roles);
|
||||||
const sorted = sortRolesByPosition(rolesList);
|
const sorted = sortRolesByPosition(rolesList);
|
||||||
if (pendingRoleOrder) {
|
const order = pendingRoleOrder ?? optimisticRoleOrder;
|
||||||
return pendingRoleOrder
|
if (order) {
|
||||||
|
const mapped = order
|
||||||
.map((id: string) => sorted.find((r: GuildRole) => r.id === id))
|
.map((id: string) => sorted.find((r: GuildRole) => r.id === id))
|
||||||
.filter((r): r is GuildRole => r != null);
|
.filter((r): r is GuildRole => r != null);
|
||||||
|
const missing = sorted.filter((r: GuildRole) => !order.includes(r.id));
|
||||||
|
return [...mapped, ...missing];
|
||||||
}
|
}
|
||||||
return sorted;
|
return sorted;
|
||||||
}, [guild, pendingRoleOrder]);
|
}, [guild, pendingRoleOrder, optimisticRoleOrder]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!pendingRoleOrder || !guild) return;
|
if (!pendingRoleOrder || !guild) return;
|
||||||
const sortedIds = sortRolesByPosition(Object.values(guild.roles)).map((role: GuildRole) => role.id);
|
const sortedIds = sortRolesByPosition(Object.values(guild.roles)).map((role: GuildRole) => role.id);
|
||||||
@@ -119,6 +123,13 @@ const GuildRolesTab: React.FC<{guildId: string}> = observer(({guildId}) => {
|
|||||||
const matches = pendingRoleOrder.every((id, index) => id === sortedIds[index]);
|
const matches = pendingRoleOrder.every((id, index) => id === sortedIds[index]);
|
||||||
if (matches) setPendingRoleOrder(null);
|
if (matches) setPendingRoleOrder(null);
|
||||||
}, [pendingRoleOrder, guild]);
|
}, [pendingRoleOrder, guild]);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!optimisticRoleOrder || !guild) return;
|
||||||
|
const sortedIds = sortRolesByPosition(Object.values(guild.roles)).map((role: GuildRole) => role.id);
|
||||||
|
if (optimisticRoleOrder.length !== sortedIds.length) return;
|
||||||
|
const matches = optimisticRoleOrder.every((id, index) => id === sortedIds[index]);
|
||||||
|
if (matches) setOptimisticRoleOrder(null);
|
||||||
|
}, [optimisticRoleOrder, guild]);
|
||||||
const hoistedRoles = useMemo(() => {
|
const hoistedRoles = useMemo(() => {
|
||||||
if (!guild) return [];
|
if (!guild) return [];
|
||||||
const rolesList = Object.values(guild.roles).filter((role) => role.hoist && !role.isEveryone);
|
const rolesList = Object.values(guild.roles).filter((role) => role.hoist && !role.isEveryone);
|
||||||
@@ -357,18 +368,20 @@ const GuildRolesTab: React.FC<{guildId: string}> = observer(({guildId}) => {
|
|||||||
const grantablePermissions = sourceRole.permissions & currentUserPermissions;
|
const grantablePermissions = sourceRole.permissions & currentUserPermissions;
|
||||||
pendingRoleCreationRef.current = true;
|
pendingRoleCreationRef.current = true;
|
||||||
try {
|
try {
|
||||||
const createdRole = await GuildCommands.createRole(guild.id, copyName);
|
const createdRole = await GuildCommands.createRole(guild.id, copyName, {
|
||||||
await GuildCommands.updateRole(guild.id, createdRole.id, {
|
|
||||||
color: sourceRole.color,
|
color: sourceRole.color,
|
||||||
|
permissions: grantablePermissions,
|
||||||
|
});
|
||||||
|
const orderedRoleIds = roles.map((role: GuildRole) => role.id).filter((id) => id !== createdRole.id);
|
||||||
|
const sourceIndex = orderedRoleIds.indexOf(sourceRoleId);
|
||||||
|
const insertIndex = sourceIndex === -1 ? orderedRoleIds.length : sourceIndex + 1;
|
||||||
|
orderedRoleIds.splice(insertIndex, 0, createdRole.id);
|
||||||
|
setOptimisticRoleOrder(orderedRoleIds);
|
||||||
|
await GuildCommands.updateRole(guild.id, createdRole.id, {
|
||||||
hoist: sourceRole.hoist,
|
hoist: sourceRole.hoist,
|
||||||
mentionable: sourceRole.mentionable,
|
mentionable: sourceRole.mentionable,
|
||||||
permissions: grantablePermissions.toString(),
|
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
const orderedRoleIds = roles.map((role: GuildRole) => role.id);
|
|
||||||
const sourceIndex = orderedRoleIds.indexOf(sourceRoleId);
|
|
||||||
const insertIndex = sourceIndex === -1 ? orderedRoleIds.length : sourceIndex + 1;
|
|
||||||
orderedRoleIds.splice(insertIndex, 0, createdRole.id);
|
|
||||||
const submittableRoleOrder = createSubmittableRoleOrderIds({
|
const submittableRoleOrder = createSubmittableRoleOrderIds({
|
||||||
guildId: guild.id,
|
guildId: guild.id,
|
||||||
orderedRoleIds,
|
orderedRoleIds,
|
||||||
@@ -384,10 +397,12 @@ const GuildRolesTab: React.FC<{guildId: string}> = observer(({guildId}) => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to position duplicated role in guild ${guild.id}:`, error);
|
logger.error(`Failed to position duplicated role in guild ${guild.id}:`, error);
|
||||||
|
setOptimisticRoleOrder(null);
|
||||||
}
|
}
|
||||||
ToastCommands.createToast({type: 'success', children: <Trans>Role created successfully</Trans>});
|
ToastCommands.createToast({type: 'success', children: <Trans>Role created successfully</Trans>});
|
||||||
} catch (_error) {
|
} catch (_error) {
|
||||||
pendingRoleCreationRef.current = false;
|
pendingRoleCreationRef.current = false;
|
||||||
|
setOptimisticRoleOrder(null);
|
||||||
ModalCommands.push(
|
ModalCommands.push(
|
||||||
modal(() => (
|
modal(() => (
|
||||||
<RoleCreateFailedModal data-flx="guild.guild-tabs.guild-roles-tab.handle-duplicate-role.role-create-failed-modal" />
|
<RoleCreateFailedModal data-flx="guild.guild-tabs.guild-roles-tab.handle-duplicate-role.role-create-failed-modal" />
|
||||||
|
|||||||
Reference in new issue
Block a user