mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-07 14:56:06 +02:00
refactor dialog commands func
This commit is contained in:
@@ -203,27 +203,11 @@ export function useAvatarDialogCommands(
|
|||||||
// --- Command map ---
|
// --- Command map ---
|
||||||
// Direct commands: function
|
// Direct commands: function
|
||||||
// String commands: delegate to component callback
|
// String commands: delegate to component callback
|
||||||
// Confirmed commands: { confirm: true, label: string, handler: fn }
|
// Confirmed commands: { confirm: () => ({title, description, ...}), handler: fn }
|
||||||
|
|
||||||
function buildCommandMap() {
|
function buildCommandMap() {
|
||||||
const D = () => avatarDialog.value;
|
const D = () => avatarDialog.value;
|
||||||
|
|
||||||
const confirmLabelMap = {
|
|
||||||
'Delete Favorite': () =>
|
|
||||||
t('dialog.avatar.actions.favorite_tooltip'),
|
|
||||||
'Select Fallback Avatar': () =>
|
|
||||||
t('dialog.avatar.actions.select_fallback'),
|
|
||||||
'Block Avatar': () => t('dialog.avatar.actions.block'),
|
|
||||||
'Unblock Avatar': () => t('dialog.avatar.actions.unblock'),
|
|
||||||
'Make Public': () => t('dialog.avatar.actions.make_public'),
|
|
||||||
'Make Private': () => t('dialog.avatar.actions.make_private'),
|
|
||||||
Delete: () => t('dialog.avatar.actions.delete'),
|
|
||||||
'Delete Imposter': () => t('dialog.avatar.actions.delete_impostor'),
|
|
||||||
'Create Imposter': () => t('dialog.avatar.actions.create_impostor'),
|
|
||||||
'Regenerate Imposter': () =>
|
|
||||||
t('dialog.avatar.actions.regenerate_impostor')
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// --- Direct commands ---
|
// --- Direct commands ---
|
||||||
Refresh: () => {
|
Refresh: () => {
|
||||||
@@ -254,15 +238,23 @@ export function useAvatarDialogCommands(
|
|||||||
|
|
||||||
// --- Confirmed commands ---
|
// --- Confirmed commands ---
|
||||||
'Delete Favorite': {
|
'Delete Favorite': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
label: confirmLabelMap['Delete Favorite'],
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.avatar.actions.favorite_tooltip')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: (id) => {
|
handler: (id) => {
|
||||||
favoriteRequest.deleteFavorite({ objectId: id });
|
favoriteRequest.deleteFavorite({ objectId: id });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Select Fallback Avatar': {
|
'Select Fallback Avatar': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
label: confirmLabelMap['Select Fallback Avatar'],
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.avatar.actions.select_fallback')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: (id) => {
|
handler: (id) => {
|
||||||
avatarRequest
|
avatarRequest
|
||||||
.selectFallbackAvatar({ avatarId: id })
|
.selectFallbackAvatar({ avatarId: id })
|
||||||
@@ -273,8 +265,12 @@ export function useAvatarDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Block Avatar': {
|
'Block Avatar': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
label: confirmLabelMap['Block Avatar'],
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.avatar.actions.block')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: (id) => {
|
handler: (id) => {
|
||||||
avatarModerationRequest
|
avatarModerationRequest
|
||||||
.sendAvatarModeration({
|
.sendAvatarModeration({
|
||||||
@@ -290,8 +286,12 @@ export function useAvatarDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Unblock Avatar': {
|
'Unblock Avatar': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
label: confirmLabelMap['Unblock Avatar'],
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.avatar.actions.unblock')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: (id) => {
|
handler: (id) => {
|
||||||
avatarModerationRequest
|
avatarModerationRequest
|
||||||
.deleteAvatarModeration({
|
.deleteAvatarModeration({
|
||||||
@@ -313,8 +313,12 @@ export function useAvatarDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Make Public': {
|
'Make Public': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
label: confirmLabelMap['Make Public'],
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.avatar.actions.make_public')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: (id) => {
|
handler: (id) => {
|
||||||
avatarRequest
|
avatarRequest
|
||||||
.saveAvatar({ id, releaseStatus: 'public' })
|
.saveAvatar({ id, releaseStatus: 'public' })
|
||||||
@@ -326,8 +330,12 @@ export function useAvatarDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Make Private': {
|
'Make Private': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
label: confirmLabelMap['Make Private'],
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.avatar.actions.make_private')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: (id) => {
|
handler: (id) => {
|
||||||
avatarRequest
|
avatarRequest
|
||||||
.saveAvatar({ id, releaseStatus: 'private' })
|
.saveAvatar({ id, releaseStatus: 'private' })
|
||||||
@@ -339,8 +347,12 @@ export function useAvatarDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Delete: {
|
Delete: {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
label: confirmLabelMap['Delete'],
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.avatar.actions.delete')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: (id) => {
|
handler: (id) => {
|
||||||
avatarRequest
|
avatarRequest
|
||||||
.deleteAvatar({ avatarId: id })
|
.deleteAvatar({ avatarId: id })
|
||||||
@@ -365,8 +377,12 @@ export function useAvatarDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Delete Imposter': {
|
'Delete Imposter': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
label: confirmLabelMap['Delete Imposter'],
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.avatar.actions.delete_impostor')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: (id) => {
|
handler: (id) => {
|
||||||
avatarRequest
|
avatarRequest
|
||||||
.deleteImposter({ avatarId: id })
|
.deleteImposter({ avatarId: id })
|
||||||
@@ -378,8 +394,12 @@ export function useAvatarDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Create Imposter': {
|
'Create Imposter': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
label: confirmLabelMap['Create Imposter'],
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.avatar.actions.create_impostor')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: (id) => {
|
handler: (id) => {
|
||||||
avatarRequest
|
avatarRequest
|
||||||
.createImposter({ avatarId: id })
|
.createImposter({ avatarId: id })
|
||||||
@@ -390,8 +410,12 @@ export function useAvatarDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Regenerate Imposter': {
|
'Regenerate Imposter': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
label: confirmLabelMap['Regenerate Imposter'],
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.avatar.actions.regenerate_impostor')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: (id) => {
|
handler: (id) => {
|
||||||
avatarRequest
|
avatarRequest
|
||||||
.deleteImposter({ avatarId: id })
|
.deleteImposter({ avatarId: id })
|
||||||
@@ -456,16 +480,7 @@ export function useAvatarDialogCommands(
|
|||||||
|
|
||||||
// Confirmed command
|
// Confirmed command
|
||||||
if (entry.confirm) {
|
if (entry.confirm) {
|
||||||
const displayLabel =
|
modalStore.confirm(entry.confirm()).then(({ ok }) => {
|
||||||
typeof entry.label === 'function' ? entry.label() : command;
|
|
||||||
modalStore
|
|
||||||
.confirm({
|
|
||||||
title: t('confirm.title'),
|
|
||||||
description: t('confirm.command_question', {
|
|
||||||
command: displayLabel
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.then(({ ok }) => {
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
entry.handler(D.id);
|
entry.handler(D.id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -413,6 +413,7 @@
|
|||||||
|
|
||||||
import DialogJsonTab from '../DialogJsonTab.vue';
|
import DialogJsonTab from '../DialogJsonTab.vue';
|
||||||
import GroupDialogInfoTab from './GroupDialogInfoTab.vue';
|
import GroupDialogInfoTab from './GroupDialogInfoTab.vue';
|
||||||
|
import { useGroupDialogCommands } from './useGroupDialogCommands';
|
||||||
import GroupDialogMembersTab from './GroupDialogMembersTab.vue';
|
import GroupDialogMembersTab from './GroupDialogMembersTab.vue';
|
||||||
import GroupDialogPhotosTab from './GroupDialogPhotosTab.vue';
|
import GroupDialogPhotosTab from './GroupDialogPhotosTab.vue';
|
||||||
import GroupDialogPostsTab from './GroupDialogPostsTab.vue';
|
import GroupDialogPostsTab from './GroupDialogPostsTab.vue';
|
||||||
@@ -444,6 +445,28 @@
|
|||||||
|
|
||||||
const { showFullscreenImageDialog } = useGalleryStore();
|
const { showFullscreenImageDialog } = useGalleryStore();
|
||||||
|
|
||||||
|
const { groupDialogCommand } = useGroupDialogCommands(groupDialog, {
|
||||||
|
t,
|
||||||
|
modalStore,
|
||||||
|
currentUser,
|
||||||
|
showGroupDialog,
|
||||||
|
leaveGroupPrompt,
|
||||||
|
setGroupVisibility,
|
||||||
|
setGroupSubscription,
|
||||||
|
showGroupMemberModerationDialog,
|
||||||
|
showInviteGroupDialog: (groupId, userId) => {
|
||||||
|
if (groupId) {
|
||||||
|
inviteGroupDialog.value.groupId = groupId;
|
||||||
|
}
|
||||||
|
if (userId) {
|
||||||
|
inviteGroupDialog.value.userId = userId;
|
||||||
|
}
|
||||||
|
inviteGroupDialog.value.visible = true;
|
||||||
|
},
|
||||||
|
showGroupPostEditDialog,
|
||||||
|
groupRequest
|
||||||
|
});
|
||||||
|
|
||||||
const groupDialogTabCurrentName = ref('0');
|
const groupDialogTabCurrentName = ref('0');
|
||||||
const treeData = ref({});
|
const treeData = ref({});
|
||||||
const membersTabRef = ref(null);
|
const membersTabRef = ref(null);
|
||||||
@@ -474,20 +497,7 @@
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param groupId
|
|
||||||
* @param userId
|
|
||||||
*/
|
|
||||||
function showInviteGroupDialog(groupId, userId) {
|
|
||||||
if (groupId) {
|
|
||||||
inviteGroupDialog.value.groupId = groupId;
|
|
||||||
}
|
|
||||||
if (userId) {
|
|
||||||
inviteGroupDialog.value.userId = userId;
|
|
||||||
}
|
|
||||||
inviteGroupDialog.value.visible = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -594,109 +604,7 @@
|
|||||||
* @param gallery
|
* @param gallery
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param command
|
|
||||||
*/
|
|
||||||
function groupDialogCommand(command) {
|
|
||||||
const D = groupDialog.value;
|
|
||||||
if (D.visible === false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (command) {
|
|
||||||
case 'Share':
|
|
||||||
copyToClipboard(groupDialog.value.ref.$url);
|
|
||||||
break;
|
|
||||||
case 'Create Post':
|
|
||||||
showGroupPostEditDialog(groupDialog.value.id, null);
|
|
||||||
break;
|
|
||||||
case 'Moderation Tools':
|
|
||||||
showGroupMemberModerationDialog(groupDialog.value.id);
|
|
||||||
break;
|
|
||||||
case 'Invite To Group':
|
|
||||||
showInviteGroupDialog(D.id, '');
|
|
||||||
break;
|
|
||||||
case 'Refresh':
|
|
||||||
const groupId = D.id;
|
|
||||||
showGroupDialog(groupId, { forceRefresh: true });
|
|
||||||
break;
|
|
||||||
case 'Leave Group':
|
|
||||||
leaveGroupPrompt(D.id);
|
|
||||||
break;
|
|
||||||
case 'Block Group':
|
|
||||||
blockGroup(D.id);
|
|
||||||
break;
|
|
||||||
case 'Unblock Group':
|
|
||||||
unblockGroup(D.id);
|
|
||||||
break;
|
|
||||||
case 'Visibility Everyone':
|
|
||||||
setGroupVisibility(D.id, 'visible');
|
|
||||||
break;
|
|
||||||
case 'Visibility Friends':
|
|
||||||
setGroupVisibility(D.id, 'friends');
|
|
||||||
break;
|
|
||||||
case 'Visibility Hidden':
|
|
||||||
setGroupVisibility(D.id, 'hidden');
|
|
||||||
break;
|
|
||||||
case 'Subscribe To Announcements':
|
|
||||||
setGroupSubscription(D.id, true);
|
|
||||||
break;
|
|
||||||
case 'Unsubscribe To Announcements':
|
|
||||||
setGroupSubscription(D.id, false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param groupId
|
|
||||||
*/
|
|
||||||
function blockGroup(groupId) {
|
|
||||||
modalStore
|
|
||||||
.confirm({
|
|
||||||
description: t('confirm.block_group'),
|
|
||||||
title: t('confirm.title')
|
|
||||||
})
|
|
||||||
.then(({ ok }) => {
|
|
||||||
if (!ok) return;
|
|
||||||
groupRequest
|
|
||||||
.blockGroup({
|
|
||||||
groupId
|
|
||||||
})
|
|
||||||
.then((args) => {
|
|
||||||
if (groupDialog.value.visible && groupDialog.value.id === args.params.groupId) {
|
|
||||||
showGroupDialog(args.params.groupId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(() => {});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param groupId
|
|
||||||
*/
|
|
||||||
function unblockGroup(groupId) {
|
|
||||||
modalStore
|
|
||||||
.confirm({
|
|
||||||
description: t('confirm.unblock_group'),
|
|
||||||
title: t('confirm.title')
|
|
||||||
})
|
|
||||||
.then(({ ok }) => {
|
|
||||||
if (!ok) return;
|
|
||||||
groupRequest
|
|
||||||
.unblockGroup({
|
|
||||||
groupId,
|
|
||||||
userId: currentUser.value.id
|
|
||||||
})
|
|
||||||
.then((args) => {
|
|
||||||
if (groupDialog.value.visible && groupDialog.value.id === args.params.groupId) {
|
|
||||||
showGroupDialog(args.params.groupId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(() => {});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
import { useGroupDialogCommands } from '../useGroupDialogCommands';
|
||||||
|
|
||||||
|
vi.mock('../../../../shared/utils', () => ({
|
||||||
|
copyToClipboard: vi.fn()
|
||||||
|
}));
|
||||||
|
|
||||||
|
const { copyToClipboard } = await import('../../../../shared/utils');
|
||||||
|
|
||||||
|
function createGroupDialog(overrides = {}) {
|
||||||
|
return ref({
|
||||||
|
visible: true,
|
||||||
|
id: 'grp_123',
|
||||||
|
ref: {
|
||||||
|
$url: 'https://vrchat.com/home/group/grp_123'
|
||||||
|
},
|
||||||
|
...overrides
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDeps(overrides = {}) {
|
||||||
|
return {
|
||||||
|
t: vi.fn((key) => key),
|
||||||
|
modalStore: {
|
||||||
|
confirm: vi.fn().mockResolvedValue({ ok: true })
|
||||||
|
},
|
||||||
|
currentUser: ref({ id: 'usr_current' }),
|
||||||
|
showGroupDialog: vi.fn(),
|
||||||
|
leaveGroupPrompt: vi.fn(),
|
||||||
|
setGroupVisibility: vi.fn(),
|
||||||
|
setGroupSubscription: vi.fn(),
|
||||||
|
showGroupMemberModerationDialog: vi.fn(),
|
||||||
|
showInviteGroupDialog: vi.fn(),
|
||||||
|
showGroupPostEditDialog: vi.fn(),
|
||||||
|
groupRequest: {
|
||||||
|
blockGroup: vi.fn().mockResolvedValue({
|
||||||
|
params: { groupId: 'grp_123' }
|
||||||
|
}),
|
||||||
|
unblockGroup: vi.fn().mockResolvedValue({
|
||||||
|
params: { groupId: 'grp_123' }
|
||||||
|
})
|
||||||
|
},
|
||||||
|
...overrides
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('useGroupDialogCommands', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns early when dialog is not visible', () => {
|
||||||
|
const groupDialog = createGroupDialog({ visible: false });
|
||||||
|
const deps = createDeps();
|
||||||
|
const { groupDialogCommand } = useGroupDialogCommands(groupDialog, deps);
|
||||||
|
|
||||||
|
groupDialogCommand('Refresh');
|
||||||
|
expect(deps.showGroupDialog).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Share copies group URL', () => {
|
||||||
|
const groupDialog = createGroupDialog();
|
||||||
|
const deps = createDeps();
|
||||||
|
const { groupDialogCommand } = useGroupDialogCommands(groupDialog, deps);
|
||||||
|
|
||||||
|
groupDialogCommand('Share');
|
||||||
|
expect(copyToClipboard).toHaveBeenCalledWith(
|
||||||
|
'https://vrchat.com/home/group/grp_123'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Invite To Group dispatches invite callback', () => {
|
||||||
|
const groupDialog = createGroupDialog();
|
||||||
|
const deps = createDeps();
|
||||||
|
const { groupDialogCommand } = useGroupDialogCommands(groupDialog, deps);
|
||||||
|
|
||||||
|
groupDialogCommand('Invite To Group');
|
||||||
|
expect(deps.showInviteGroupDialog).toHaveBeenCalledWith('grp_123', '');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Refresh calls showGroupDialog with forceRefresh', () => {
|
||||||
|
const groupDialog = createGroupDialog();
|
||||||
|
const deps = createDeps();
|
||||||
|
const { groupDialogCommand } = useGroupDialogCommands(groupDialog, deps);
|
||||||
|
|
||||||
|
groupDialogCommand('Refresh');
|
||||||
|
expect(deps.showGroupDialog).toHaveBeenCalledWith('grp_123', {
|
||||||
|
forceRefresh: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Block Group confirms and calls blockGroup', async () => {
|
||||||
|
const groupDialog = createGroupDialog();
|
||||||
|
const deps = createDeps();
|
||||||
|
const { groupDialogCommand } = useGroupDialogCommands(groupDialog, deps);
|
||||||
|
|
||||||
|
groupDialogCommand('Block Group');
|
||||||
|
await vi.waitFor(() => {
|
||||||
|
expect(deps.modalStore.confirm).toHaveBeenCalled();
|
||||||
|
expect(deps.groupRequest.blockGroup).toHaveBeenCalledWith({
|
||||||
|
groupId: 'grp_123'
|
||||||
|
});
|
||||||
|
expect(deps.showGroupDialog).toHaveBeenCalledWith('grp_123');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Unblock Group confirms and calls unblockGroup', async () => {
|
||||||
|
const groupDialog = createGroupDialog();
|
||||||
|
const deps = createDeps();
|
||||||
|
const { groupDialogCommand } = useGroupDialogCommands(groupDialog, deps);
|
||||||
|
|
||||||
|
groupDialogCommand('Unblock Group');
|
||||||
|
await vi.waitFor(() => {
|
||||||
|
expect(deps.modalStore.confirm).toHaveBeenCalled();
|
||||||
|
expect(deps.groupRequest.unblockGroup).toHaveBeenCalledWith({
|
||||||
|
groupId: 'grp_123',
|
||||||
|
userId: 'usr_current'
|
||||||
|
});
|
||||||
|
expect(deps.showGroupDialog).toHaveBeenCalledWith('grp_123');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not run confirmed action when confirmation is cancelled', async () => {
|
||||||
|
const groupDialog = createGroupDialog();
|
||||||
|
const deps = createDeps({
|
||||||
|
modalStore: {
|
||||||
|
confirm: vi.fn().mockResolvedValue({ ok: false })
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const { groupDialogCommand } = useGroupDialogCommands(groupDialog, deps);
|
||||||
|
|
||||||
|
groupDialogCommand('Block Group');
|
||||||
|
await vi.waitFor(() => {
|
||||||
|
expect(deps.modalStore.confirm).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
expect(deps.groupRequest.blockGroup).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
import { copyToClipboard } from '../../../shared/utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Composable for GroupDialog command dispatch.
|
||||||
|
* Uses a command map pattern consistent with Avatar/World/User dialogs.
|
||||||
|
* @param {import('vue').Ref} groupDialog - reactive ref to the group dialog state
|
||||||
|
* @param {object} deps - external dependencies
|
||||||
|
* @param deps.t
|
||||||
|
* @param deps.modalStore
|
||||||
|
* @param deps.currentUser
|
||||||
|
* @param deps.showGroupDialog
|
||||||
|
* @param deps.leaveGroupPrompt
|
||||||
|
* @param deps.setGroupVisibility
|
||||||
|
* @param deps.setGroupSubscription
|
||||||
|
* @param deps.showGroupMemberModerationDialog
|
||||||
|
* @param deps.showInviteGroupDialog
|
||||||
|
* @param deps.showGroupPostEditDialog
|
||||||
|
* @param deps.groupRequest
|
||||||
|
* @returns {object} command composable API
|
||||||
|
*/
|
||||||
|
export function useGroupDialogCommands(
|
||||||
|
groupDialog,
|
||||||
|
{
|
||||||
|
t,
|
||||||
|
modalStore,
|
||||||
|
currentUser,
|
||||||
|
showGroupDialog,
|
||||||
|
leaveGroupPrompt,
|
||||||
|
setGroupVisibility,
|
||||||
|
setGroupSubscription,
|
||||||
|
showGroupMemberModerationDialog,
|
||||||
|
showInviteGroupDialog,
|
||||||
|
showGroupPostEditDialog,
|
||||||
|
groupRequest
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
// --- Command map ---
|
||||||
|
// Direct commands: function
|
||||||
|
// Confirmed commands: { confirm: () => ({title, description, ...}), handler: fn }
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function buildCommandMap() {
|
||||||
|
const D = () => groupDialog.value;
|
||||||
|
|
||||||
|
return {
|
||||||
|
// --- Direct commands ---
|
||||||
|
Share: () => {
|
||||||
|
copyToClipboard(D().ref.$url);
|
||||||
|
},
|
||||||
|
'Create Post': () => {
|
||||||
|
showGroupPostEditDialog(D().id, null);
|
||||||
|
},
|
||||||
|
'Moderation Tools': () => {
|
||||||
|
showGroupMemberModerationDialog(D().id);
|
||||||
|
},
|
||||||
|
'Invite To Group': () => {
|
||||||
|
showInviteGroupDialog(D().id, '');
|
||||||
|
},
|
||||||
|
Refresh: () => {
|
||||||
|
showGroupDialog(D().id, { forceRefresh: true });
|
||||||
|
},
|
||||||
|
'Leave Group': () => {
|
||||||
|
leaveGroupPrompt(D().id);
|
||||||
|
},
|
||||||
|
'Visibility Everyone': () => {
|
||||||
|
setGroupVisibility(D().id, 'visible');
|
||||||
|
},
|
||||||
|
'Visibility Friends': () => {
|
||||||
|
setGroupVisibility(D().id, 'friends');
|
||||||
|
},
|
||||||
|
'Visibility Hidden': () => {
|
||||||
|
setGroupVisibility(D().id, 'hidden');
|
||||||
|
},
|
||||||
|
'Subscribe To Announcements': () => {
|
||||||
|
setGroupSubscription(D().id, true);
|
||||||
|
},
|
||||||
|
'Unsubscribe To Announcements': () => {
|
||||||
|
setGroupSubscription(D().id, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
// --- Confirmed commands ---
|
||||||
|
'Block Group': {
|
||||||
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.block_group')
|
||||||
|
}),
|
||||||
|
handler: (id) => {
|
||||||
|
groupRequest.blockGroup({ groupId: id }).then((args) => {
|
||||||
|
if (
|
||||||
|
groupDialog.value.visible &&
|
||||||
|
groupDialog.value.id === args.params.groupId
|
||||||
|
) {
|
||||||
|
showGroupDialog(args.params.groupId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Unblock Group': {
|
||||||
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.unblock_group')
|
||||||
|
}),
|
||||||
|
handler: (id) => {
|
||||||
|
groupRequest
|
||||||
|
.unblockGroup({
|
||||||
|
groupId: id,
|
||||||
|
userId: currentUser.value.id
|
||||||
|
})
|
||||||
|
.then((args) => {
|
||||||
|
if (
|
||||||
|
groupDialog.value.visible &&
|
||||||
|
groupDialog.value.id === args.params.groupId
|
||||||
|
) {
|
||||||
|
showGroupDialog(args.params.groupId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const commandMap = buildCommandMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch a group dialog command.
|
||||||
|
* @param {string} command
|
||||||
|
*/
|
||||||
|
function groupDialogCommand(command) {
|
||||||
|
const D = groupDialog.value;
|
||||||
|
if (D.visible === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const entry = commandMap[command];
|
||||||
|
|
||||||
|
if (!entry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Direct function
|
||||||
|
if (typeof entry === 'function') {
|
||||||
|
entry();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirmed command
|
||||||
|
if (entry.confirm) {
|
||||||
|
modalStore
|
||||||
|
.confirm(entry.confirm())
|
||||||
|
.then(({ ok }) => {
|
||||||
|
if (ok) {
|
||||||
|
entry.handler(D.id);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
groupDialogCommand
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -216,7 +216,7 @@ export function useUserDialogCommands(
|
|||||||
|
|
||||||
// --- Command map ---
|
// --- Command map ---
|
||||||
// Direct commands: function
|
// Direct commands: function
|
||||||
// Confirmed commands: { confirm: true, handler: fn }
|
// Confirmed commands: { confirm: () => ({title, description, ...}), handler: fn }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -360,7 +360,12 @@ export function useUserDialogCommands(
|
|||||||
|
|
||||||
// --- Confirmed commands ---
|
// --- Confirmed commands ---
|
||||||
'Delete Favorite': {
|
'Delete Favorite': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.user.actions.delete_favorite')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: (userId) => {
|
handler: (userId) => {
|
||||||
favoriteRequest.deleteFavorite({
|
favoriteRequest.deleteFavorite({
|
||||||
objectId: userId
|
objectId: userId
|
||||||
@@ -368,7 +373,12 @@ export function useUserDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Accept Friend Request': {
|
'Accept Friend Request': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.user.actions.accept_friend_request')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: async (userId) => {
|
handler: async (userId) => {
|
||||||
const key = getFriendRequest(userId);
|
const key = getFriendRequest(userId);
|
||||||
if (key === '') {
|
if (key === '') {
|
||||||
@@ -401,7 +411,12 @@ export function useUserDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Decline Friend Request': {
|
'Decline Friend Request': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.user.actions.decline_friend_request')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: async (userId) => {
|
handler: async (userId) => {
|
||||||
const key = getFriendRequest(userId);
|
const key = getFriendRequest(userId);
|
||||||
if (key === '') {
|
if (key === '') {
|
||||||
@@ -423,7 +438,12 @@ export function useUserDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Cancel Friend Request': {
|
'Cancel Friend Request': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.user.actions.cancel_friend_request')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: async (userId) => {
|
handler: async (userId) => {
|
||||||
const args = await friendRequest.cancelFriendRequest({
|
const args = await friendRequest.cancelFriendRequest({
|
||||||
userId
|
userId
|
||||||
@@ -432,7 +452,12 @@ export function useUserDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Send Friend Request': {
|
'Send Friend Request': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.user.actions.send_friend_request')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: async (userId) => {
|
handler: async (userId) => {
|
||||||
const args = await friendRequest.sendFriendRequest({
|
const args = await friendRequest.sendFriendRequest({
|
||||||
userId
|
userId
|
||||||
@@ -441,7 +466,12 @@ export function useUserDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Moderation Unblock': {
|
'Moderation Unblock': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.user.actions.moderation_unblock')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: async (userId) => {
|
handler: async (userId) => {
|
||||||
const args =
|
const args =
|
||||||
await playerModerationRequest.deletePlayerModeration({
|
await playerModerationRequest.deletePlayerModeration({
|
||||||
@@ -452,7 +482,12 @@ export function useUserDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Moderation Block': {
|
'Moderation Block': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.user.actions.moderation_block')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: async (userId) => {
|
handler: async (userId) => {
|
||||||
const args =
|
const args =
|
||||||
await playerModerationRequest.sendPlayerModeration({
|
await playerModerationRequest.sendPlayerModeration({
|
||||||
@@ -463,7 +498,12 @@ export function useUserDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Moderation Unmute': {
|
'Moderation Unmute': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.user.actions.moderation_unmute')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: async (userId) => {
|
handler: async (userId) => {
|
||||||
const args =
|
const args =
|
||||||
await playerModerationRequest.deletePlayerModeration({
|
await playerModerationRequest.deletePlayerModeration({
|
||||||
@@ -474,7 +514,12 @@ export function useUserDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Moderation Mute': {
|
'Moderation Mute': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.user.actions.moderation_mute')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: async (userId) => {
|
handler: async (userId) => {
|
||||||
const args =
|
const args =
|
||||||
await playerModerationRequest.sendPlayerModeration({
|
await playerModerationRequest.sendPlayerModeration({
|
||||||
@@ -485,7 +530,14 @@ export function useUserDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Moderation Enable Avatar Interaction': {
|
'Moderation Enable Avatar Interaction': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t(
|
||||||
|
'dialog.user.actions.moderation_enable_avatar_interaction'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: async (userId) => {
|
handler: async (userId) => {
|
||||||
const args =
|
const args =
|
||||||
await playerModerationRequest.deletePlayerModeration({
|
await playerModerationRequest.deletePlayerModeration({
|
||||||
@@ -496,7 +548,14 @@ export function useUserDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Moderation Disable Avatar Interaction': {
|
'Moderation Disable Avatar Interaction': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t(
|
||||||
|
'dialog.user.actions.moderation_disable_avatar_interaction'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: async (userId) => {
|
handler: async (userId) => {
|
||||||
const args =
|
const args =
|
||||||
await playerModerationRequest.sendPlayerModeration({
|
await playerModerationRequest.sendPlayerModeration({
|
||||||
@@ -507,7 +566,14 @@ export function useUserDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Moderation Enable Chatbox': {
|
'Moderation Enable Chatbox': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t(
|
||||||
|
'dialog.user.actions.moderation_enable_chatbox'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: async (userId) => {
|
handler: async (userId) => {
|
||||||
const args =
|
const args =
|
||||||
await playerModerationRequest.deletePlayerModeration({
|
await playerModerationRequest.deletePlayerModeration({
|
||||||
@@ -518,7 +584,14 @@ export function useUserDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Moderation Disable Chatbox': {
|
'Moderation Disable Chatbox': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t(
|
||||||
|
'dialog.user.actions.moderation_disable_chatbox'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: async (userId) => {
|
handler: async (userId) => {
|
||||||
const args =
|
const args =
|
||||||
await playerModerationRequest.sendPlayerModeration({
|
await playerModerationRequest.sendPlayerModeration({
|
||||||
@@ -529,7 +602,12 @@ export function useUserDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'Report Hacking': {
|
'Report Hacking': {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.user.actions.report_hacking')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: (userId) => {
|
handler: (userId) => {
|
||||||
miscRequest.reportUser({
|
miscRequest.reportUser({
|
||||||
userId,
|
userId,
|
||||||
@@ -540,7 +618,12 @@ export function useUserDialogCommands(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Unfriend: {
|
Unfriend: {
|
||||||
confirm: true,
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.user.actions.unfriend')
|
||||||
|
})
|
||||||
|
}),
|
||||||
handler: async (userId) => {
|
handler: async (userId) => {
|
||||||
const args = await friendRequest.deleteFriend(
|
const args = await friendRequest.deleteFriend(
|
||||||
{
|
{
|
||||||
@@ -601,23 +684,8 @@ export function useUserDialogCommands(
|
|||||||
|
|
||||||
// Confirmed command
|
// Confirmed command
|
||||||
if (entry.confirm) {
|
if (entry.confirm) {
|
||||||
const i18nPreFix = 'dialog.user.actions.';
|
|
||||||
const formattedCommand = command.toLowerCase().replace(/ /g, '_');
|
|
||||||
const displayCommandText = t(
|
|
||||||
`${i18nPreFix}${formattedCommand}`
|
|
||||||
).includes('i18nPreFix')
|
|
||||||
? command
|
|
||||||
: t(`${i18nPreFix}${formattedCommand}`);
|
|
||||||
|
|
||||||
modalStore
|
modalStore
|
||||||
.confirm({
|
.confirm(entry.confirm())
|
||||||
description: t('confirm.message', {
|
|
||||||
command: displayCommandText
|
|
||||||
}),
|
|
||||||
title: t('confirm.title'),
|
|
||||||
confirmText: t('confirm.confirm_button'),
|
|
||||||
cancelText: t('confirm.cancel_button')
|
|
||||||
})
|
|
||||||
.then(({ ok }) => {
|
.then(({ ok }) => {
|
||||||
if (ok) {
|
if (ok) {
|
||||||
entry.handler(D.id);
|
entry.handler(D.id);
|
||||||
|
|||||||
@@ -385,7 +385,6 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
useAdvancedSettingsStore,
|
useAdvancedSettingsStore,
|
||||||
useAppearanceSettingsStore,
|
|
||||||
useFavoriteStore,
|
useFavoriteStore,
|
||||||
useGalleryStore,
|
useGalleryStore,
|
||||||
useGameStore,
|
useGameStore,
|
||||||
@@ -442,7 +441,9 @@
|
|||||||
worldDialogCommand,
|
worldDialogCommand,
|
||||||
onFileChangeWorldImage,
|
onFileChangeWorldImage,
|
||||||
onCropConfirmWorld,
|
onCropConfirmWorld,
|
||||||
copyWorldName
|
copyWorldName,
|
||||||
|
showWorldAllowedDomainsDialog,
|
||||||
|
registerCallbacks
|
||||||
} = useWorldDialogCommands(worldDialog, {
|
} = useWorldDialogCommands(worldDialog, {
|
||||||
t,
|
t,
|
||||||
toast,
|
toast,
|
||||||
@@ -456,6 +457,18 @@
|
|||||||
showFullscreenImageDialog
|
showFullscreenImageDialog
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registerCallbacks({
|
||||||
|
showSetWorldTagsDialog: () => {
|
||||||
|
isSetWorldTagsDialogVisible.value = true;
|
||||||
|
},
|
||||||
|
showWorldAllowedDomainsDialog: () => {
|
||||||
|
showWorldAllowedDomainsDialog();
|
||||||
|
},
|
||||||
|
showChangeWorldImageDialog: () => {
|
||||||
|
document.getElementById('WorldImageUploadButton').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const worldDialogTabs = computed(() => [
|
const worldDialogTabs = computed(() => [
|
||||||
{ value: 'Instances', label: t('dialog.world.instances.header') },
|
{ value: 'Instances', label: t('dialog.world.instances.header') },
|
||||||
{ value: 'Info', label: t('dialog.world.info.header') },
|
{ value: 'Info', label: t('dialog.world.info.header') },
|
||||||
|
|||||||
@@ -184,8 +184,17 @@ describe('useWorldDialogCommands', () => {
|
|||||||
test('Change Tags sets isSetWorldTagsDialogVisible to true', () => {
|
test('Change Tags sets isSetWorldTagsDialogVisible to true', () => {
|
||||||
const worldDialog = createWorldDialog();
|
const worldDialog = createWorldDialog();
|
||||||
const deps = createDeps();
|
const deps = createDeps();
|
||||||
const { worldDialogCommand, isSetWorldTagsDialogVisible } =
|
const {
|
||||||
useWorldDialogCommands(worldDialog, deps);
|
worldDialogCommand,
|
||||||
|
isSetWorldTagsDialogVisible,
|
||||||
|
registerCallbacks
|
||||||
|
} = useWorldDialogCommands(worldDialog, deps);
|
||||||
|
|
||||||
|
registerCallbacks({
|
||||||
|
showSetWorldTagsDialog: () => {
|
||||||
|
isSetWorldTagsDialogVisible.value = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
worldDialogCommand('Change Tags');
|
worldDialogCommand('Change Tags');
|
||||||
expect(isSetWorldTagsDialogVisible.value).toBe(true);
|
expect(isSetWorldTagsDialogVisible.value).toBe(true);
|
||||||
@@ -225,8 +234,18 @@ describe('useWorldDialogCommands', () => {
|
|||||||
test('Change Allowed Domains opens the allowed domains dialog', () => {
|
test('Change Allowed Domains opens the allowed domains dialog', () => {
|
||||||
const worldDialog = createWorldDialog();
|
const worldDialog = createWorldDialog();
|
||||||
const deps = createDeps();
|
const deps = createDeps();
|
||||||
const { worldDialogCommand, worldAllowedDomainsDialog } =
|
const {
|
||||||
useWorldDialogCommands(worldDialog, deps);
|
worldDialogCommand,
|
||||||
|
worldAllowedDomainsDialog,
|
||||||
|
showWorldAllowedDomainsDialog,
|
||||||
|
registerCallbacks
|
||||||
|
} = useWorldDialogCommands(worldDialog, deps);
|
||||||
|
|
||||||
|
registerCallbacks({
|
||||||
|
showWorldAllowedDomainsDialog: () => {
|
||||||
|
showWorldAllowedDomainsDialog();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
worldDialogCommand('Change Allowed Domains');
|
worldDialogCommand('Change Allowed Domains');
|
||||||
expect(worldAllowedDomainsDialog.value.visible).toBe(true);
|
expect(worldAllowedDomainsDialog.value.visible).toBe(true);
|
||||||
|
|||||||
@@ -57,13 +57,6 @@ export function useWorldDialogCommands(
|
|||||||
const cropDialogFile = ref(null);
|
const cropDialogFile = ref(null);
|
||||||
const changeWorldImageLoading = ref(false);
|
const changeWorldImageLoading = ref(false);
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function showChangeWorldImageDialog() {
|
|
||||||
document.getElementById('WorldImageUploadButton').click();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param e
|
* @param e
|
||||||
@@ -372,207 +365,240 @@ export function useWorldDialogCommands(
|
|||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Command map ---
|
||||||
|
// Direct commands: function
|
||||||
|
// String commands: delegate to component callback
|
||||||
|
// Confirmed commands: { confirm: () => ({title, description, ...}), handler: fn }
|
||||||
|
|
||||||
|
function buildCommandMap() {
|
||||||
|
const D = () => worldDialog.value;
|
||||||
|
|
||||||
|
return {
|
||||||
|
// --- Direct commands ---
|
||||||
|
Refresh: () => {
|
||||||
|
const { tag, shortName } = D().$location;
|
||||||
|
showWorldDialog(tag, shortName, { forceRefresh: true });
|
||||||
|
},
|
||||||
|
Share: () => {
|
||||||
|
copyWorldUrl();
|
||||||
|
},
|
||||||
|
'Previous Instances': () => {
|
||||||
|
showPreviousInstancesListDialog(D().ref);
|
||||||
|
},
|
||||||
|
'New Instance': () => {
|
||||||
|
showNewInstanceDialog(D().$location.tag);
|
||||||
|
},
|
||||||
|
'New Instance and Self Invite': () => {
|
||||||
|
newInstanceSelfInvite(D().id);
|
||||||
|
},
|
||||||
|
'Add Favorite': () => {
|
||||||
|
showFavoriteDialog('world', D().id);
|
||||||
|
},
|
||||||
|
'Download Unity Package': () => {
|
||||||
|
openExternalLink(replaceVrcPackageUrl(D().ref.unityPackageUrl));
|
||||||
|
},
|
||||||
|
Rename: () => {
|
||||||
|
promptRenameWorld(D());
|
||||||
|
},
|
||||||
|
'Change Description': () => {
|
||||||
|
promptChangeWorldDescription(D());
|
||||||
|
},
|
||||||
|
'Change Capacity': () => {
|
||||||
|
promptChangeWorldCapacity(D());
|
||||||
|
},
|
||||||
|
'Change Recommended Capacity': () => {
|
||||||
|
promptChangeWorldRecommendedCapacity(D());
|
||||||
|
},
|
||||||
|
'Change YouTube Preview': () => {
|
||||||
|
promptChangeWorldYouTubePreview(D());
|
||||||
|
},
|
||||||
|
|
||||||
|
// --- Delegated to component ---
|
||||||
|
'Change Tags': 'showSetWorldTagsDialog',
|
||||||
|
'Change Allowed Domains': 'showWorldAllowedDomainsDialog',
|
||||||
|
'Change Image': 'showChangeWorldImageDialog',
|
||||||
|
|
||||||
|
// --- Confirmed commands ---
|
||||||
|
'Delete Favorite': {
|
||||||
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.world.actions.favorites_tooltip')
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
handler: (id) => {
|
||||||
|
favoriteRequest.deleteFavorite({ objectId: id });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Make Home': {
|
||||||
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.world.actions.make_home')
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
handler: (id) => {
|
||||||
|
userRequest
|
||||||
|
.saveCurrentUser({ homeLocation: id })
|
||||||
|
.then((args) => {
|
||||||
|
toast.success(t('message.world.home_updated'));
|
||||||
|
return args;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Reset Home': {
|
||||||
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.world.actions.reset_home')
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
handler: () => {
|
||||||
|
userRequest
|
||||||
|
.saveCurrentUser({ homeLocation: '' })
|
||||||
|
.then((args) => {
|
||||||
|
toast.success(t('message.world.home_reset'));
|
||||||
|
return args;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Publish: {
|
||||||
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.world.actions.publish_to_labs')
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
handler: (id) => {
|
||||||
|
worldRequest.publishWorld({ worldId: id }).then((args) => {
|
||||||
|
toast.success(t('message.world.published'));
|
||||||
|
return args;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Unpublish: {
|
||||||
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.world.actions.unpublish')
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
handler: (id) => {
|
||||||
|
worldRequest
|
||||||
|
.unpublishWorld({ worldId: id })
|
||||||
|
.then((args) => {
|
||||||
|
toast.success(t('message.world.unpublished'));
|
||||||
|
return args;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Delete Persistent Data': {
|
||||||
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t(
|
||||||
|
'dialog.world.actions.delete_persistent_data'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
handler: (id) => {
|
||||||
|
miscRequest
|
||||||
|
.deleteWorldPersistData({ worldId: id })
|
||||||
|
.then((args) => {
|
||||||
|
if (
|
||||||
|
args.params.worldId === worldDialog.value.id &&
|
||||||
|
worldDialog.value.visible
|
||||||
|
) {
|
||||||
|
worldDialog.value.hasPersistData = false;
|
||||||
|
}
|
||||||
|
toast.success(
|
||||||
|
t('message.world.persistent_data_deleted')
|
||||||
|
);
|
||||||
|
return args;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Delete: {
|
||||||
|
confirm: () => ({
|
||||||
|
title: t('confirm.title'),
|
||||||
|
description: t('confirm.command_question', {
|
||||||
|
command: t('dialog.world.actions.delete')
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
handler: (id) => {
|
||||||
|
worldRequest.deleteWorld({ worldId: id }).then((args) => {
|
||||||
|
const { json } = args;
|
||||||
|
cachedWorlds.delete(json.id);
|
||||||
|
if (worldDialog.value.ref.authorId === json.authorId) {
|
||||||
|
const map = new Map();
|
||||||
|
for (const ref of cachedWorlds.values()) {
|
||||||
|
if (ref.authorId === json.authorId) {
|
||||||
|
map.set(ref.id, ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const array = Array.from(map.values());
|
||||||
|
userDialog.value.worlds = array;
|
||||||
|
}
|
||||||
|
toast.success(t('message.world.deleted'));
|
||||||
|
worldDialog.value.visible = false;
|
||||||
|
return args;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const commandMap = buildCommandMap();
|
||||||
|
|
||||||
|
// Callbacks for string-type commands (delegated to component)
|
||||||
|
let componentCallbacks = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Register component-level callbacks for string-type commands.
|
||||||
* @param command
|
* @param {object} callbacks
|
||||||
|
*/
|
||||||
|
function registerCallbacks(callbacks) {
|
||||||
|
componentCallbacks = callbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch a world dialog command.
|
||||||
|
* @param {string} command
|
||||||
*/
|
*/
|
||||||
function worldDialogCommand(command) {
|
function worldDialogCommand(command) {
|
||||||
const D = worldDialog.value;
|
const D = worldDialog.value;
|
||||||
if (D.visible === false) {
|
if (D.visible === false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (command) {
|
|
||||||
case 'Delete Favorite':
|
const entry = commandMap[command];
|
||||||
case 'Make Home':
|
|
||||||
case 'Reset Home':
|
if (!entry) {
|
||||||
case 'Publish':
|
return;
|
||||||
case 'Unpublish':
|
}
|
||||||
case 'Delete Persistent Data':
|
|
||||||
case 'Delete':
|
// String entry => delegate to component callback
|
||||||
const commandLabelMap = {
|
if (typeof entry === 'string') {
|
||||||
'Delete Favorite': t(
|
const cb = componentCallbacks[entry];
|
||||||
'dialog.world.actions.favorites_tooltip'
|
if (cb) {
|
||||||
),
|
cb();
|
||||||
'Make Home': t('dialog.world.actions.make_home'),
|
}
|
||||||
'Reset Home': t('dialog.world.actions.reset_home'),
|
return;
|
||||||
Publish: t('dialog.world.actions.publish_to_labs'),
|
}
|
||||||
Unpublish: t('dialog.world.actions.unpublish'),
|
|
||||||
'Delete Persistent Data': t(
|
// Direct function
|
||||||
'dialog.world.actions.delete_persistent_data'
|
if (typeof entry === 'function') {
|
||||||
),
|
entry();
|
||||||
Delete: t('dialog.world.actions.delete')
|
return;
|
||||||
};
|
}
|
||||||
modalStore
|
|
||||||
.confirm({
|
// Confirmed command
|
||||||
description: t('confirm.command_question', {
|
if (entry.confirm) {
|
||||||
command: commandLabelMap[command] ?? command
|
modalStore.confirm(entry.confirm()).then(({ ok }) => {
|
||||||
}),
|
if (ok) {
|
||||||
title: t('confirm.title')
|
entry.handler(D.id);
|
||||||
})
|
|
||||||
.then(({ ok }) => {
|
|
||||||
if (!ok) return;
|
|
||||||
switch (command) {
|
|
||||||
case 'Delete Favorite':
|
|
||||||
favoriteRequest.deleteFavorite({
|
|
||||||
objectId: D.id
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case 'Make Home':
|
|
||||||
userRequest
|
|
||||||
.saveCurrentUser({
|
|
||||||
homeLocation: D.id
|
|
||||||
})
|
|
||||||
.then((args) => {
|
|
||||||
toast.success(
|
|
||||||
t('message.world.home_updated')
|
|
||||||
);
|
|
||||||
return args;
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case 'Reset Home':
|
|
||||||
userRequest
|
|
||||||
.saveCurrentUser({
|
|
||||||
homeLocation: ''
|
|
||||||
})
|
|
||||||
.then((args) => {
|
|
||||||
toast.success(
|
|
||||||
t('message.world.home_reset')
|
|
||||||
);
|
|
||||||
return args;
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case 'Publish':
|
|
||||||
worldRequest
|
|
||||||
.publishWorld({
|
|
||||||
worldId: D.id
|
|
||||||
})
|
|
||||||
.then((args) => {
|
|
||||||
toast.success(
|
|
||||||
t('message.world.published')
|
|
||||||
);
|
|
||||||
return args;
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case 'Unpublish':
|
|
||||||
worldRequest
|
|
||||||
.unpublishWorld({
|
|
||||||
worldId: D.id
|
|
||||||
})
|
|
||||||
.then((args) => {
|
|
||||||
toast.success(
|
|
||||||
t('message.world.unpublished')
|
|
||||||
);
|
|
||||||
return args;
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case 'Delete Persistent Data':
|
|
||||||
miscRequest
|
|
||||||
.deleteWorldPersistData({
|
|
||||||
worldId: D.id
|
|
||||||
})
|
|
||||||
.then((args) => {
|
|
||||||
if (
|
|
||||||
args.params.worldId ===
|
|
||||||
worldDialog.value.id &&
|
|
||||||
worldDialog.value.visible
|
|
||||||
) {
|
|
||||||
worldDialog.value.hasPersistData = false;
|
|
||||||
}
|
}
|
||||||
toast.success(
|
|
||||||
t(
|
|
||||||
'message.world.persistent_data_deleted'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return args;
|
|
||||||
});
|
});
|
||||||
break;
|
|
||||||
case 'Delete':
|
|
||||||
worldRequest
|
|
||||||
.deleteWorld({
|
|
||||||
worldId: D.id
|
|
||||||
})
|
|
||||||
.then((args) => {
|
|
||||||
const { json } = args;
|
|
||||||
cachedWorlds.delete(json.id);
|
|
||||||
if (
|
|
||||||
worldDialog.value.ref.authorId ===
|
|
||||||
json.authorId
|
|
||||||
) {
|
|
||||||
const map = new Map();
|
|
||||||
for (const ref of cachedWorlds.values()) {
|
|
||||||
if (
|
|
||||||
ref.authorId ===
|
|
||||||
json.authorId
|
|
||||||
) {
|
|
||||||
map.set(ref.id, ref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const array = Array.from(
|
|
||||||
map.values()
|
|
||||||
);
|
|
||||||
userDialog.value.worlds = array;
|
|
||||||
}
|
|
||||||
toast.success(
|
|
||||||
t('message.world.deleted')
|
|
||||||
);
|
|
||||||
D.visible = false;
|
|
||||||
return args;
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {});
|
|
||||||
break;
|
|
||||||
case 'Previous Instances':
|
|
||||||
showPreviousInstancesListDialog(D.ref);
|
|
||||||
break;
|
|
||||||
case 'Share':
|
|
||||||
copyWorldUrl();
|
|
||||||
break;
|
|
||||||
case 'Change Allowed Domains':
|
|
||||||
showWorldAllowedDomainsDialog();
|
|
||||||
break;
|
|
||||||
case 'Change Tags':
|
|
||||||
isSetWorldTagsDialogVisible.value = true;
|
|
||||||
break;
|
|
||||||
case 'Download Unity Package':
|
|
||||||
openExternalLink(
|
|
||||||
replaceVrcPackageUrl(worldDialog.value.ref.unityPackageUrl)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 'Change Image':
|
|
||||||
showChangeWorldImageDialog();
|
|
||||||
break;
|
|
||||||
case 'Refresh':
|
|
||||||
const { tag, shortName } = worldDialog.value.$location;
|
|
||||||
showWorldDialog(tag, shortName, { forceRefresh: true });
|
|
||||||
break;
|
|
||||||
case 'New Instance':
|
|
||||||
showNewInstanceDialog(D.$location.tag);
|
|
||||||
break;
|
|
||||||
case 'Add Favorite':
|
|
||||||
showFavoriteDialog('world', D.id);
|
|
||||||
break;
|
|
||||||
case 'New Instance and Self Invite':
|
|
||||||
newInstanceSelfInvite(D.id);
|
|
||||||
break;
|
|
||||||
case 'Rename':
|
|
||||||
promptRenameWorld(D);
|
|
||||||
break;
|
|
||||||
case 'Change Description':
|
|
||||||
promptChangeWorldDescription(D);
|
|
||||||
break;
|
|
||||||
case 'Change Capacity':
|
|
||||||
promptChangeWorldCapacity(D);
|
|
||||||
break;
|
|
||||||
case 'Change Recommended Capacity':
|
|
||||||
promptChangeWorldRecommendedCapacity(D);
|
|
||||||
break;
|
|
||||||
case 'Change YouTube Preview':
|
|
||||||
promptChangeWorldYouTubePreview(D);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -596,6 +622,7 @@ export function useWorldDialogCommands(
|
|||||||
promptChangeWorldDescription,
|
promptChangeWorldDescription,
|
||||||
promptChangeWorldCapacity,
|
promptChangeWorldCapacity,
|
||||||
promptChangeWorldRecommendedCapacity,
|
promptChangeWorldRecommendedCapacity,
|
||||||
promptChangeWorldYouTubePreview
|
promptChangeWorldYouTubePreview,
|
||||||
|
registerCallbacks
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2076,7 +2076,7 @@
|
|||||||
"send_invite": "Continue? Send Invite",
|
"send_invite": "Continue? Send Invite",
|
||||||
"decline_type": "Continue? Decline {type}",
|
"decline_type": "Continue? Decline {type}",
|
||||||
"delete_type": "Continue? {type}",
|
"delete_type": "Continue? {type}",
|
||||||
"command_question": "Continue? {command}",
|
"command_question": "Are you sure you want to {command}?",
|
||||||
"clear_group": "Continue? Clear Group",
|
"clear_group": "Continue? Clear Group",
|
||||||
"delete_group": "Continue? Delete Group {name}",
|
"delete_group": "Continue? Delete Group {name}",
|
||||||
"delete_post": "Are you sure you want to delete this post?",
|
"delete_post": "Are you sure you want to delete this post?",
|
||||||
|
|||||||
Reference in New Issue
Block a user