diff --git a/src/components/timeline/TimelinePerformancePanel.tsx b/src/components/timeline/TimelinePerformancePanel.tsx
index 849f6a69..90ece4da 100644
--- a/src/components/timeline/TimelinePerformancePanel.tsx
+++ b/src/components/timeline/TimelinePerformancePanel.tsx
@@ -18,6 +18,8 @@ import Button from "@/components/common/button/Button";
import ChartLegend from "@/components/common/chart/ChartLegend";
import Drawer from "@/components/common/drawer/Drawer";
import { DropdownMenu } from "@/components/common/dropdownmenu/DropdownMenu";
+import ChartErrorFallback from "@/components/common/error/ChartErrorFallback";
+import { ErrorBoundary } from "@/components/common/error/ErrorBoundary";
import { Skeleton } from "@/components/common/skeleton/Skeleton";
import TimelinePeriodSelector from "@/components/timeline/TimelinePeriodSelector";
@@ -367,13 +369,24 @@ export default function TimelinePerformancePanel({
disableNext={!canGoNext}
/>
-
+
+
+
diff --git a/src/pages/dashboard/timeline/Timeline.tsx b/src/pages/dashboard/timeline/Timeline.tsx
index ca5b4117..077c7279 100644
--- a/src/pages/dashboard/timeline/Timeline.tsx
+++ b/src/pages/dashboard/timeline/Timeline.tsx
@@ -22,6 +22,8 @@ import { useTimelineDetail } from "@/hooks/timeline/useTimelineDetail";
import { useTimelineList } from "@/hooks/timeline/useTimelineList";
import Button from "@/components/common/button/Button";
+import AreaErrorFallback from "@/components/common/error/AreaErrorFallback";
+import { ErrorBoundary } from "@/components/common/error/ErrorBoundary";
import Modal from "@/components/common/modal/Modal";
import ModalContent from "@/components/common/modal/ModalContent";
import TimelineSkeleton from "@/components/timeline/skeleton/TimelineSkeleton";
@@ -279,115 +281,121 @@ export default function Timeline() {
className="flex w-full min-w-0 flex-col"
style={{ height: TIMELINE_PAGE_HEIGHT }}
>
-
-
-
-
-
-
-
-
-
-
-
-
-
- Sort
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sort
+
+
+
+ Filter
+
+
-
- {hasNoTimelines ? (
- setIsCreateOpen(true)} />
- ) : (
-
+ {hasNoTimelines ? (
+
setIsCreateOpen(true)} />
+ ) : (
-
- {hasNoVisibleBars ? (
-
-
- 이 기간에 표시할 타임라인이 없어요
-
-
- 다른 기간으로 이동하거나 보기 단위를 변경해 보세요
-
-
- ) : (
-
+
- {bars.map((bar) => (
- handleEditTimeline(bar.id)}
- onDelete={() =>
- handleDeleteTimeline({ id: bar.id, name: bar.title })
- }
- />
- ))}
-
- )}
+ className="sticky top-0"
+ />
+ {hasNoVisibleBars ? (
+
+
+ 이 기간에 표시할 타임라인이 없어요
+
+
+ 다른 기간으로 이동하거나 보기 단위를 변경해 보세요
+
+
+ ) : (
+
+ {bars.map((bar) => (
+ handleEditTimeline(bar.id)}
+ onDelete={() =>
+ handleDeleteTimeline({ id: bar.id, name: bar.title })
+ }
+ />
+ ))}
+
+ )}
+
-
- )}
-
+ )}
+
+
+
{/* 생성 */}
) : (
- {
- if (!value) {
+
+ {
+ if (!value) {
+ setDraftOrgNotif((prev) => ({
+ ...prev,
+ masterEnabled: false,
+ slackEnabled: false,
+ discordEnabled: false,
+ }));
+ setDraftChannel({ browserPush: false, emailNotif: false });
+ setDraftWorkspaceNotif({
+ clickAlarm: false,
+ weeklyReport: false,
+ });
+ return;
+ }
setDraftOrgNotif((prev) => ({
...prev,
- masterEnabled: false,
- slackEnabled: false,
- discordEnabled: false,
+ masterEnabled: true,
+ slackEnabled:
+ prev.slackConnected && savedOrgNotif.slackEnabled,
+ discordEnabled:
+ prev.discordConnected && savedOrgNotif.discordEnabled,
}));
- setDraftChannel({ browserPush: false, emailNotif: false });
- setDraftWorkspaceNotif({
- clickAlarm: false,
- weeklyReport: false,
- });
- return;
+ setDraftChannel(savedChannel);
+ setDraftWorkspaceNotif(savedWorkspaceNotif);
+ }}
+ browserPush={draftChannel.browserPush}
+ emailNotif={draftChannel.emailNotif}
+ onBrowserPushChange={(value) =>
+ setDraftChannel((prev) => ({ ...prev, browserPush: value }))
}
- setDraftOrgNotif((prev) => ({
- ...prev,
- masterEnabled: true,
- slackEnabled: prev.slackConnected && savedOrgNotif.slackEnabled,
- discordEnabled:
- prev.discordConnected && savedOrgNotif.discordEnabled,
- }));
- setDraftChannel(savedChannel);
- setDraftWorkspaceNotif(savedWorkspaceNotif);
- }}
- browserPush={draftChannel.browserPush}
- emailNotif={draftChannel.emailNotif}
- onBrowserPushChange={(value) =>
- setDraftChannel((prev) => ({ ...prev, browserPush: value }))
- }
- onEmailNotifChange={(value) =>
- setDraftChannel((prev) => ({ ...prev, emailNotif: value }))
- }
- slackEnabled={draftOrgNotif.slackEnabled}
- slackConnected={draftOrgNotif.slackConnected}
- slackWebhookUrl={slackWebhookUrl}
- slackWebhookError={slackWebhookError}
- onSlackWebhookUrlChange={(value) => {
- setSlackWebhookUrl(value);
- if (slackWebhookError) setSlackWebhookError("");
- }}
- onSlackEnabledChange={(value) =>
- setDraftOrgNotif((prev) => ({ ...prev, slackEnabled: value }))
- }
- onConnectSlack={handleConnectSlack}
- onDisconnectSlack={handleDisconnectSlack}
- discordEnabled={draftOrgNotif.discordEnabled}
- discordConnected={draftOrgNotif.discordConnected}
- discordWebhookUrl={discordWebhookUrl}
- discordWebhookError={discordWebhookError}
- onDiscordWebhookUrlChange={(value) => {
- setDiscordWebhookUrl(value);
- if (discordWebhookError) setDiscordWebhookError("");
- }}
- onDiscordEnabledChange={(value) =>
- setDraftOrgNotif((prev) => ({ ...prev, discordEnabled: value }))
- }
- onConnectDiscord={handleConnectDiscord}
- onDisconnectDiscord={handleDisconnectDiscord}
- workspaceName={currentWorkspaceName}
- clickAlarm={draftWorkspaceNotif.clickAlarm}
- weeklyReport={draftWorkspaceNotif.weeklyReport}
- onClickAlarmChange={(value) =>
- setDraftWorkspaceNotif((prev) => ({ ...prev, clickAlarm: value }))
- }
- onWeeklyReportChange={(value) =>
- setDraftWorkspaceNotif((prev) => ({
- ...prev,
- weeklyReport: value,
- }))
- }
- workspaceNotifiDisabled={workspaceNotifiDisabled}
- pendingOrgAction={pendingOrgAction}
- />
+ onEmailNotifChange={(value) =>
+ setDraftChannel((prev) => ({ ...prev, emailNotif: value }))
+ }
+ slackEnabled={draftOrgNotif.slackEnabled}
+ slackConnected={draftOrgNotif.slackConnected}
+ slackWebhookUrl={slackWebhookUrl}
+ slackWebhookError={slackWebhookError}
+ onSlackWebhookUrlChange={(value) => {
+ setSlackWebhookUrl(value);
+ if (slackWebhookError) setSlackWebhookError("");
+ }}
+ onSlackEnabledChange={(value) =>
+ setDraftOrgNotif((prev) => ({ ...prev, slackEnabled: value }))
+ }
+ onConnectSlack={handleConnectSlack}
+ onDisconnectSlack={handleDisconnectSlack}
+ discordEnabled={draftOrgNotif.discordEnabled}
+ discordConnected={draftOrgNotif.discordConnected}
+ discordWebhookUrl={discordWebhookUrl}
+ discordWebhookError={discordWebhookError}
+ onDiscordWebhookUrlChange={(value) => {
+ setDiscordWebhookUrl(value);
+ if (discordWebhookError) setDiscordWebhookError("");
+ }}
+ onDiscordEnabledChange={(value) =>
+ setDraftOrgNotif((prev) => ({ ...prev, discordEnabled: value }))
+ }
+ onConnectDiscord={handleConnectDiscord}
+ onDisconnectDiscord={handleDisconnectDiscord}
+ workspaceName={currentWorkspaceName}
+ clickAlarm={draftWorkspaceNotif.clickAlarm}
+ weeklyReport={draftWorkspaceNotif.weeklyReport}
+ onClickAlarmChange={(value) =>
+ setDraftWorkspaceNotif((prev) => ({
+ ...prev,
+ clickAlarm: value,
+ }))
+ }
+ onWeeklyReportChange={(value) =>
+ setDraftWorkspaceNotif((prev) => ({
+ ...prev,
+ weeklyReport: value,
+ }))
+ }
+ workspaceNotifiDisabled={workspaceNotifiDisabled}
+ pendingOrgAction={pendingOrgAction}
+ />
+
)}
diff --git a/src/pages/workspace/MemberManagement.tsx b/src/pages/workspace/MemberManagement.tsx
index 985a5bfc..6094667c 100644
--- a/src/pages/workspace/MemberManagement.tsx
+++ b/src/pages/workspace/MemberManagement.tsx
@@ -14,6 +14,8 @@ import { useCoreMutation, useCoreQuery } from "@/hooks/customQuery";
import { useNotificationMembers } from "@/hooks/setting/useNotificationMembers";
import { useUpdateNotificationMembers } from "@/hooks/setting/useUpdateNotificationMembers";
+import AreaErrorFallback from "@/components/common/error/AreaErrorFallback";
+import { ErrorBoundary } from "@/components/common/error/ErrorBoundary";
import DeleteMemberModal from "@/components/workspace/DeleteMemberModal";
import MemberList from "@/components/workspace/MemberList";
import MemberManagementLoading from "@/components/workspace/MemberManagementLoading";
@@ -339,36 +341,41 @@ export default function MemberManagement() {
return (
);
}
diff --git a/src/pages/workspace/Workspace.tsx b/src/pages/workspace/Workspace.tsx
index e4d4c732..6db5c093 100644
--- a/src/pages/workspace/Workspace.tsx
+++ b/src/pages/workspace/Workspace.tsx
@@ -13,6 +13,8 @@ import type { TCreateOrgRequest } from "@/types/workspace/workspace";
import { useCoreMutation, useCoreQuery } from "@/hooks/customQuery";
import Button from "@/components/common/button/Button";
+import AreaErrorFallback from "@/components/common/error/AreaErrorFallback";
+import { ErrorBoundary } from "@/components/common/error/ErrorBoundary";
import Input from "@/components/common/input/Input";
import Modal from "@/components/common/modal/Modal";
import TextareaField from "@/components/common/textarea/TextareaField";
@@ -211,8 +213,12 @@ export default function WorkspacePage() {
생성하기
-
- {renderWorkspaceContent()}
+
+ {renderWorkspaceContent()}
+
diff --git a/src/pages/workspace/WorkspaceSetting.tsx b/src/pages/workspace/WorkspaceSetting.tsx
index f7c7c049..eb19dbba 100644
--- a/src/pages/workspace/WorkspaceSetting.tsx
+++ b/src/pages/workspace/WorkspaceSetting.tsx
@@ -6,6 +6,8 @@ import { useCoreMutation, useCoreQuery } from "@/hooks/customQuery";
import Button from "@/components/common/button/Button";
import Card from "@/components/common/card/Card";
+import AreaErrorFallback from "@/components/common/error/AreaErrorFallback";
+import { ErrorBoundary } from "@/components/common/error/ErrorBoundary";
import Input from "@/components/common/input/Input";
import Modal from "@/components/common/modal/Modal";
import ModalContent from "@/components/common/modal/ModalContent";
@@ -203,165 +205,170 @@ export default function WorkspaceSetting() {
)}
{!loading && !errorMsg && (
- <>
-
-
-
-
- 로고 이미지
-
-
-
-
-
-
- setName(e.target.value)}
- disabled={!isAdmin || saving || deleting}
- />
- setDesc(e.target.value)}
- minRows={4}
- className="min-h-90"
- disabled={!isAdmin || saving || deleting}
- />
-
-
- {isAdmin && (
-
-
- 워크스페이스 삭제
-
-
- {saving ? "저장 중.." : "변경사항 저장하기"}
-
-
- )}
-
+ )}
+
-
{
- if (!deleting) {
- setDeleteOpen(false);
- setDeleteNameSnapshot("");
- setDeleteConfirmInput("");
- }
- }}
- title="워크스페이스를 삭제할게요"
- size="lg"
- disableOverlayClick={deleting}
- >
-
- }
- title="워크스페이스를 삭제할게요"
- description={
- <>
-
- 삭제하면 연결된 모든 데이터가 사라지고, 다시 되돌릴 수
- 없어요.
-
-
- 아래 워크스페이스 이름을 그대로 입력해 주세요.
-
- >
- }
- confirmMatchSubheading={false}
- confirmMatchText={deleteNameSnapshot}
- confirmInput={deleteConfirmInput}
- onConfirmInputChange={setDeleteConfirmInput}
- confirmMatchInputPlaceholder="워크스페이스 이름"
- buttonText="영구 삭제"
- onConfirm={() => {
- void onDelete();
+ {
+ if (!deleting) {
+ setDeleteOpen(false);
+ setDeleteNameSnapshot("");
+ setDeleteConfirmInput("");
+ }
}}
- isLoading={deleting}
- variant="danger"
- />
-
- >
+ title="워크스페이스를 삭제할게요"
+ size="lg"
+ disableOverlayClick={deleting}
+ >
+
+ }
+ title="워크스페이스를 삭제할게요"
+ description={
+ <>
+
+ 삭제하면 연결된 모든 데이터가 사라지고, 다시 되돌릴 수
+ 없어요.
+
+
+ 아래 워크스페이스 이름을 그대로 입력해 주세요.
+
+ >
+ }
+ confirmMatchSubheading={false}
+ confirmMatchText={deleteNameSnapshot}
+ confirmInput={deleteConfirmInput}
+ onConfirmInputChange={setDeleteConfirmInput}
+ confirmMatchInputPlaceholder="워크스페이스 이름"
+ buttonText="영구 삭제"
+ onConfirm={() => {
+ void onDelete();
+ }}
+ isLoading={deleting}
+ variant="danger"
+ />
+
+ >
+
)}
);