Add multi-workspace selector scope
This commit is contained in:
@@ -15,7 +15,7 @@ export const useCampaignsStore = defineStore('campaigns', () => {
|
||||
const error = ref(null);
|
||||
|
||||
async function fetchCampaigns() {
|
||||
if (!authStore.isAuthenticated || !workspaceStore.activeWorkspaceId) {
|
||||
if (!authStore.isAuthenticated) {
|
||||
campaigns.value = [];
|
||||
error.value = null;
|
||||
return;
|
||||
@@ -27,11 +27,13 @@ export const useCampaignsStore = defineStore('campaigns', () => {
|
||||
try {
|
||||
const response = await client.get('/api/campaigns', {
|
||||
params: {
|
||||
workspaceId: workspaceStore.activeWorkspaceId,
|
||||
workspaceId: workspaceStore.activeWorkspaceId ?? undefined,
|
||||
},
|
||||
});
|
||||
|
||||
campaigns.value = response.data ?? [];
|
||||
campaigns.value = (response.data ?? []).filter(campaign =>
|
||||
workspaceStore.isWorkspaceVisible(campaign.workspaceId)
|
||||
);
|
||||
} catch (fetchError) {
|
||||
console.error('Failed to fetch campaigns:', fetchError);
|
||||
campaigns.value = [];
|
||||
@@ -75,9 +77,9 @@ export const useCampaignsStore = defineStore('campaigns', () => {
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [authStore.isAuthenticated, workspaceStore.activeWorkspaceId],
|
||||
async ([isAuthenticated, workspaceId]) => {
|
||||
if (!isAuthenticated || !workspaceId) {
|
||||
() => [authStore.isAuthenticated, workspaceStore.workspaceScopeKey],
|
||||
async ([isAuthenticated]) => {
|
||||
if (!isAuthenticated) {
|
||||
campaigns.value = [];
|
||||
error.value = null;
|
||||
return;
|
||||
|
||||
@@ -14,6 +14,7 @@ export const useChannelsStore = defineStore('channels', () => {
|
||||
const isCreating = ref(false);
|
||||
const error = ref(null);
|
||||
const loadedWorkspaceId = ref(null);
|
||||
const allWorkspacesKey = '__all__';
|
||||
|
||||
const availableNetworks = [
|
||||
'Instagram',
|
||||
@@ -28,15 +29,16 @@ export const useChannelsStore = defineStore('channels', () => {
|
||||
|
||||
async function fetchChannels({ force = false } = {}) {
|
||||
const currentWorkspaceId = workspaceStore.activeWorkspaceId;
|
||||
const currentScopeKey = currentWorkspaceId ?? workspaceStore.workspaceScopeKey ?? allWorkspacesKey;
|
||||
|
||||
if (!authStore.isAuthenticated || !currentWorkspaceId) {
|
||||
if (!authStore.isAuthenticated) {
|
||||
channels.value = [];
|
||||
error.value = null;
|
||||
loadedWorkspaceId.value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!force && loadedWorkspaceId.value === currentWorkspaceId) {
|
||||
if (!force && loadedWorkspaceId.value === currentScopeKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -46,12 +48,14 @@ export const useChannelsStore = defineStore('channels', () => {
|
||||
try {
|
||||
const response = await client.get('/api/channels', {
|
||||
params: {
|
||||
workspaceId: currentWorkspaceId,
|
||||
workspaceId: currentWorkspaceId ?? undefined,
|
||||
},
|
||||
});
|
||||
|
||||
channels.value = response.data ?? [];
|
||||
loadedWorkspaceId.value = currentWorkspaceId;
|
||||
channels.value = (response.data ?? []).filter(channel =>
|
||||
workspaceStore.isWorkspaceVisible(channel.workspaceId)
|
||||
);
|
||||
loadedWorkspaceId.value = currentScopeKey;
|
||||
} catch (fetchError) {
|
||||
console.error('Failed to fetch channels:', fetchError);
|
||||
channels.value = [];
|
||||
@@ -101,9 +105,9 @@ export const useChannelsStore = defineStore('channels', () => {
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [authStore.isAuthenticated, workspaceStore.activeWorkspaceId],
|
||||
async ([isAuthenticated, workspaceId]) => {
|
||||
if (!isAuthenticated || !workspaceId) {
|
||||
() => [authStore.isAuthenticated, workspaceStore.workspaceScopeKey],
|
||||
async ([isAuthenticated]) => {
|
||||
if (!isAuthenticated) {
|
||||
channels.value = [];
|
||||
error.value = null;
|
||||
loadedWorkspaceId.value = null;
|
||||
|
||||
@@ -47,10 +47,12 @@
|
||||
.filter(channel => channel.network)
|
||||
.map(channel => {
|
||||
const metrics = buildMetrics(channel.name);
|
||||
const workspace = workspaceStore.workspaces.find(candidate => candidate.id === channel.workspaceId);
|
||||
|
||||
return {
|
||||
...channel,
|
||||
...metrics,
|
||||
workspaceName: workspace?.name ?? t('nav.noWorkspace'),
|
||||
};
|
||||
})
|
||||
);
|
||||
@@ -215,7 +217,7 @@
|
||||
>
|
||||
<div class="channel-header">
|
||||
<strong>{{ channel.name }}</strong>
|
||||
<span>{{ workspaceStore.activeWorkspace?.name || t('nav.noWorkspace') }}</span>
|
||||
<span>{{ channel.workspaceName }}</span>
|
||||
</div>
|
||||
|
||||
<div class="channel-metrics">
|
||||
|
||||
@@ -25,7 +25,7 @@ export const useClientsStore = defineStore('clients', () => {
|
||||
});
|
||||
|
||||
async function fetchClients() {
|
||||
if (!authStore.isAuthenticated || !workspaceStore.activeWorkspaceId) {
|
||||
if (!authStore.isAuthenticated) {
|
||||
clients.value = [];
|
||||
error.value = null;
|
||||
return;
|
||||
@@ -37,11 +37,13 @@ export const useClientsStore = defineStore('clients', () => {
|
||||
try {
|
||||
const response = await client.get('/api/clients', {
|
||||
params: {
|
||||
workspaceId: workspaceStore.activeWorkspaceId,
|
||||
workspaceId: workspaceStore.activeWorkspaceId ?? undefined,
|
||||
},
|
||||
});
|
||||
|
||||
clients.value = response.data ?? [];
|
||||
clients.value = (response.data ?? []).filter(candidate =>
|
||||
workspaceStore.isWorkspaceVisible(candidate.workspaceId)
|
||||
);
|
||||
} catch (fetchError) {
|
||||
console.error('Failed to fetch clients:', fetchError);
|
||||
clients.value = [];
|
||||
@@ -153,9 +155,9 @@ export const useClientsStore = defineStore('clients', () => {
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [authStore.isAuthenticated, workspaceStore.activeWorkspaceId],
|
||||
async ([isAuthenticated, workspaceId]) => {
|
||||
if (!isAuthenticated || !workspaceId) {
|
||||
() => [authStore.isAuthenticated, workspaceStore.workspaceScopeKey],
|
||||
async ([isAuthenticated]) => {
|
||||
if (!isAuthenticated) {
|
||||
clients.value = [];
|
||||
error.value = null;
|
||||
return;
|
||||
|
||||
@@ -24,6 +24,10 @@ export const useContentItemDetailStore = defineStore('content-item-detail', () =
|
||||
status: false,
|
||||
});
|
||||
|
||||
function currentItemWorkspaceId() {
|
||||
return item.value?.workspaceId ?? workspaceStore.activeWorkspaceId;
|
||||
}
|
||||
|
||||
function reset() {
|
||||
item.value = null;
|
||||
revisions.value = [];
|
||||
@@ -54,7 +58,7 @@ export const useContentItemDetailStore = defineStore('content-item-detail', () =
|
||||
client.get('/api/approvals', { params: { contentItemId } }),
|
||||
client.get('/api/notifications', {
|
||||
params: {
|
||||
workspaceId: workspaceStore.activeWorkspaceId,
|
||||
workspaceId: workspaceStore.activeWorkspaceId ?? undefined,
|
||||
contentItemId,
|
||||
},
|
||||
}),
|
||||
@@ -97,7 +101,7 @@ export const useContentItemDetailStore = defineStore('content-item-detail', () =
|
||||
const response = await client.post('/api/assets/google-drive', {
|
||||
...payload,
|
||||
contentItemId,
|
||||
workspaceId: workspaceStore.activeWorkspaceId,
|
||||
workspaceId: currentItemWorkspaceId(),
|
||||
});
|
||||
if (response.data) {
|
||||
assets.value = [...assets.value, response.data];
|
||||
@@ -131,7 +135,7 @@ export const useContentItemDetailStore = defineStore('content-item-detail', () =
|
||||
const response = await client.post('/api/comments', {
|
||||
...payload,
|
||||
contentItemId,
|
||||
workspaceId: workspaceStore.activeWorkspaceId,
|
||||
workspaceId: currentItemWorkspaceId(),
|
||||
});
|
||||
if (response.data) {
|
||||
comments.value = [...comments.value, response.data];
|
||||
@@ -202,7 +206,7 @@ export const useContentItemDetailStore = defineStore('content-item-detail', () =
|
||||
async function fetchNotifications(contentItemId) {
|
||||
const response = await client.get('/api/notifications', {
|
||||
params: {
|
||||
workspaceId: workspaceStore.activeWorkspaceId,
|
||||
workspaceId: currentItemWorkspaceId() ?? undefined,
|
||||
contentItemId,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ export const useContentItemsStore = defineStore('content-items', () => {
|
||||
);
|
||||
|
||||
async function fetchContentItems(filters = {}) {
|
||||
if (!authStore.isAuthenticated || !workspaceStore.activeWorkspaceId) {
|
||||
if (!authStore.isAuthenticated) {
|
||||
items.value = [];
|
||||
error.value = null;
|
||||
return;
|
||||
@@ -32,13 +32,15 @@ export const useContentItemsStore = defineStore('content-items', () => {
|
||||
try {
|
||||
const response = await client.get('/api/content-items', {
|
||||
params: {
|
||||
workspaceId: workspaceStore.activeWorkspaceId,
|
||||
workspaceId: workspaceStore.activeWorkspaceId ?? undefined,
|
||||
clientId: filters.clientId,
|
||||
campaignId: filters.campaignId,
|
||||
},
|
||||
});
|
||||
|
||||
items.value = response.data ?? [];
|
||||
items.value = (response.data ?? []).filter(item =>
|
||||
workspaceStore.isWorkspaceVisible(item.workspaceId)
|
||||
);
|
||||
} catch (fetchError) {
|
||||
console.error('Failed to fetch content items:', fetchError);
|
||||
items.value = [];
|
||||
@@ -86,9 +88,9 @@ export const useContentItemsStore = defineStore('content-items', () => {
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [authStore.isAuthenticated, workspaceStore.activeWorkspaceId],
|
||||
async ([isAuthenticated, workspaceId]) => {
|
||||
if (!isAuthenticated || !workspaceId) {
|
||||
() => [authStore.isAuthenticated, workspaceStore.workspaceScopeKey],
|
||||
async ([isAuthenticated]) => {
|
||||
if (!isAuthenticated) {
|
||||
items.value = [];
|
||||
error.value = null;
|
||||
return;
|
||||
|
||||
@@ -11,6 +11,7 @@ export const useWorkspaceStore = defineStore('workspace', () => {
|
||||
|
||||
const workspaces = ref([]);
|
||||
const activeWorkspaceId = ref(null);
|
||||
const visibleWorkspaceIds = ref([]);
|
||||
const isLoading = ref(false);
|
||||
const isCreating = ref(false);
|
||||
const isUpdating = ref(false);
|
||||
@@ -25,11 +26,43 @@ export const useWorkspaceStore = defineStore('workspace', () => {
|
||||
const activeWorkspace = computed(() =>
|
||||
workspaces.value.find(workspace => workspace.id === activeWorkspaceId.value) ?? null
|
||||
);
|
||||
const isAllWorkspacesSelected = computed(() =>
|
||||
activeWorkspaceId.value === null && workspaces.value.length > 1
|
||||
);
|
||||
const visibleWorkspaceCount = computed(() =>
|
||||
activeWorkspaceId.value ? 1 : visibleWorkspaceIds.value.length
|
||||
);
|
||||
const areAllWorkspacesVisible = computed(() =>
|
||||
activeWorkspaceId.value === null &&
|
||||
workspaces.value.length > 1 &&
|
||||
visibleWorkspaceIds.value.length === workspaces.value.length
|
||||
);
|
||||
const visibleWorkspaceIdSet = computed(() => new Set(visibleWorkspaceIds.value));
|
||||
const workspaceScopeKey = computed(() =>
|
||||
activeWorkspaceId.value ?? visibleWorkspaceIds.value.slice().sort().join(',')
|
||||
);
|
||||
|
||||
function allWorkspaceIds() {
|
||||
return workspaces.value.map(workspace => workspace.id);
|
||||
}
|
||||
|
||||
function normalizeVisibleWorkspaces() {
|
||||
const workspaceIds = allWorkspaceIds();
|
||||
const knownWorkspaceIds = new Set(workspaceIds);
|
||||
const nextVisibleWorkspaceIds = visibleWorkspaceIds.value.filter(workspaceId =>
|
||||
knownWorkspaceIds.has(workspaceId)
|
||||
);
|
||||
|
||||
visibleWorkspaceIds.value = nextVisibleWorkspaceIds.length > 0
|
||||
? nextVisibleWorkspaceIds
|
||||
: workspaceIds;
|
||||
}
|
||||
|
||||
async function fetchWorkspaces() {
|
||||
if (!authStore.isAuthenticated) {
|
||||
workspaces.value = [];
|
||||
activeWorkspaceId.value = null;
|
||||
visibleWorkspaceIds.value = [];
|
||||
error.value = null;
|
||||
return;
|
||||
}
|
||||
@@ -40,9 +73,10 @@ export const useWorkspaceStore = defineStore('workspace', () => {
|
||||
try {
|
||||
const response = await client.get('/api/workspaces');
|
||||
workspaces.value = response.data ?? [];
|
||||
normalizeVisibleWorkspaces();
|
||||
|
||||
if (!workspaces.value.some(workspace => workspace.id === activeWorkspaceId.value)) {
|
||||
activeWorkspaceId.value = workspaces.value[0]?.id ?? null;
|
||||
activeWorkspaceId.value = workspaces.value.length > 1 ? null : workspaces.value[0]?.id ?? null;
|
||||
}
|
||||
|
||||
organizationStore.setSelectedOrganizationFromWorkspace(activeWorkspace.value);
|
||||
@@ -75,6 +109,7 @@ export const useWorkspaceStore = defineStore('workspace', () => {
|
||||
workspaces.value = [...workspaces.value, response.data]
|
||||
.sort((left, right) => left.name.localeCompare(right.name));
|
||||
activeWorkspaceId.value = response.data.id;
|
||||
visibleWorkspaceIds.value = [response.data.id];
|
||||
|
||||
try {
|
||||
await client.post('/api/clients', {
|
||||
@@ -172,10 +207,62 @@ export const useWorkspaceStore = defineStore('workspace', () => {
|
||||
|
||||
if (workspaces.value.some(workspace => workspace.id === workspaceId)) {
|
||||
activeWorkspaceId.value = workspaceId;
|
||||
visibleWorkspaceIds.value = [workspaceId];
|
||||
organizationStore.setSelectedOrganizationFromWorkspace(activeWorkspace.value);
|
||||
}
|
||||
}
|
||||
|
||||
function setAllWorkspaces() {
|
||||
if (workspaces.value.length > 1) {
|
||||
activeWorkspaceId.value = null;
|
||||
visibleWorkspaceIds.value = allWorkspaceIds();
|
||||
}
|
||||
}
|
||||
|
||||
function isWorkspaceVisible(workspaceId) {
|
||||
if (activeWorkspaceId.value) {
|
||||
return workspaceId === activeWorkspaceId.value;
|
||||
}
|
||||
|
||||
if (visibleWorkspaceIds.value.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return visibleWorkspaceIdSet.value.has(workspaceId);
|
||||
}
|
||||
|
||||
function toggleWorkspaceVisibility(workspaceId) {
|
||||
if (!workspaces.value.some(workspace => workspace.id === workspaceId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const wasFocusedOnSingleWorkspace = Boolean(activeWorkspaceId.value);
|
||||
activeWorkspaceId.value = null;
|
||||
const visibleIds = new Set(
|
||||
wasFocusedOnSingleWorkspace || visibleWorkspaceIds.value.length === 0
|
||||
? allWorkspaceIds()
|
||||
: visibleWorkspaceIds.value
|
||||
);
|
||||
|
||||
if (visibleIds.has(workspaceId)) {
|
||||
visibleIds.delete(workspaceId);
|
||||
} else {
|
||||
visibleIds.add(workspaceId);
|
||||
}
|
||||
|
||||
if (visibleIds.size === 0) {
|
||||
visibleIds.add(workspaceId);
|
||||
}
|
||||
|
||||
const nextVisibleWorkspaceIds = allWorkspaceIds().filter(id => visibleIds.has(id));
|
||||
if (nextVisibleWorkspaceIds.length === 1) {
|
||||
setActiveWorkspace(nextVisibleWorkspaceIds[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
visibleWorkspaceIds.value = nextVisibleWorkspaceIds;
|
||||
}
|
||||
|
||||
async function fetchInvites(workspaceId = activeWorkspaceId.value) {
|
||||
if (!authStore.isAuthenticated || !workspaceId) {
|
||||
invitesByWorkspace.value = {};
|
||||
@@ -257,6 +344,7 @@ export const useWorkspaceStore = defineStore('workspace', () => {
|
||||
if (!isAuthenticated) {
|
||||
workspaces.value = [];
|
||||
activeWorkspaceId.value = null;
|
||||
visibleWorkspaceIds.value = [];
|
||||
error.value = null;
|
||||
return;
|
||||
}
|
||||
@@ -270,6 +358,11 @@ export const useWorkspaceStore = defineStore('workspace', () => {
|
||||
workspaces,
|
||||
activeWorkspaceId,
|
||||
activeWorkspace,
|
||||
visibleWorkspaceIds,
|
||||
isAllWorkspacesSelected,
|
||||
visibleWorkspaceCount,
|
||||
areAllWorkspacesVisible,
|
||||
workspaceScopeKey,
|
||||
isLoading,
|
||||
isCreating,
|
||||
isUpdating,
|
||||
@@ -288,5 +381,8 @@ export const useWorkspaceStore = defineStore('workspace', () => {
|
||||
fetchMembers,
|
||||
inviteMember,
|
||||
setActiveWorkspace,
|
||||
setAllWorkspaces,
|
||||
isWorkspaceVisible,
|
||||
toggleWorkspaceVisibility,
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user