This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useSpaces, useArchiveSpace } from '../../hooks/useSpaces';
|
||||
@@ -425,21 +425,39 @@ function SpaceChat({
|
||||
const qc = useQueryClient();
|
||||
const auth = useAuthState();
|
||||
const { data: allTasks } = useLocalTaskList();
|
||||
const { data: spaces } = useSpaces();
|
||||
const [showCreate, setShowCreate] = useState(false);
|
||||
const { search: searchQuery, status: selectedStatus, sort: sortMode, scope } = filter;
|
||||
const setScope = (val: TaskScope) => onFilterChange({ scope: val });
|
||||
const setSearchQuery = (val: string) => onFilterChange({ search: val });
|
||||
const setSelectedStatus = (val: 'all' | StatusColumn) => onFilterChange({ status: val });
|
||||
const setSortMode = (val: SortMode) => onFilterChange({ sort: val });
|
||||
const spaceTasks = filterTasksForSpace(allTasks ?? [], spaceId, isPersonalSpace);
|
||||
|
||||
// 自分/他メンバーの切替。共有ワークスペースで「他の人のタスク」が存在するときだけ
|
||||
// 出す(個人ワークスペースや単独利用では意味がないので隠す)。スコープ分割は Tasks
|
||||
// ページと同じ filterTasksByScope を再利用する(owner_id null は others 側、という
|
||||
// 既存規約に合わせる)。フィルタ状態は URL に永続化されるため、スペース切替時は App の
|
||||
// onSelectSpace が search/status/sort/scope を明示リセットする(remount 依存ではない)。
|
||||
const userId = auth.mode === 'authenticated' ? auth.user.id : null;
|
||||
const hasOthersTasks = userId != null && spaceTasks.some(t => t.ownerId !== userId);
|
||||
// 認証無効 (no-auth 単独利用) は admin 同等に扱う(App.tsx の isAdmin と同じ規約)。
|
||||
const isAdmin = auth.mode === 'authenticated' ? auth.user.role === 'admin' : true;
|
||||
// case スペースの id 集合。個人バケツ判定(null か case でない id = 誰かの個人
|
||||
// スペース)に使う。admin の listSpaces は全 case スペースを返すので集合は完全。
|
||||
const caseSpaceIds = useMemo(
|
||||
() => new Set((spaces ?? []).filter(s => s.kind === 'case').map(s => s.id)),
|
||||
[spaces],
|
||||
);
|
||||
|
||||
let spaceTasks = filterTasksForSpace(allTasks ?? [], spaceId, isPersonalSpace, caseSpaceIds);
|
||||
// 可視性ルール: 個人ワークスペースは本人専用。admin だけが他ユーザーの個人コンテンツを
|
||||
// 「他のメンバー」タブで監視できる。非 admin の個人スペースは自分の所有分に絞り、他人を
|
||||
// 一切出さない(リスト API が public/org 等を返しても個人 WS には混ぜない)。
|
||||
if (isPersonalSpace && !isAdmin && userId != null) {
|
||||
spaceTasks = spaceTasks.filter(t => t.ownerId === userId);
|
||||
}
|
||||
|
||||
// 自分/他メンバーの切替。共有ワークスペースのメンバー間、または個人スペースを admin が
|
||||
// 監視するときに「他の人のタスク」が存在する場合だけ出す。スコープ分割は Tasks ページと
|
||||
// 同じ filterTasksByScope を再利用する(owner_id null は others 側、という既存規約に合わ
|
||||
// せる)。フィルタ状態は URL に永続化されるため、スペース切替時は App の onSelectSpace が
|
||||
// search/status/sort/scope を明示リセットする(remount 依存ではない)。
|
||||
const othersAllowed = !isPersonalSpace || isAdmin;
|
||||
const hasOthersTasks = othersAllowed && userId != null && spaceTasks.some(t => t.ownerId !== userId);
|
||||
const tasks = userId != null && hasOthersTasks
|
||||
? filterTasksByScope(spaceTasks, scope, userId)
|
||||
: spaceTasks;
|
||||
|
||||
Reference in New Issue
Block a user