|
|
@@ -1,10 +1,14 @@
|
|
|
import { Tab, Tabs } from "@nextui-org/react";
|
|
|
-import React, { useMemo, useState } from "react";
|
|
|
+import React, { useEffect, useMemo, useState } from "react";
|
|
|
import { useTranslation } from "react-i18next";
|
|
|
import { IoIosGlobe } from "react-icons/io";
|
|
|
import { VscCode } from "react-icons/vsc";
|
|
|
+import { useSelector } from "react-redux";
|
|
|
import Calendar from "../assets/calendar";
|
|
|
import { I18nKey } from "../i18n/declaration";
|
|
|
+import { initialState as initialBrowserState } from "../state/browserSlice";
|
|
|
+import { initialState as initialCodeState } from "../state/codeSlice";
|
|
|
+import { RootState } from "../store";
|
|
|
import { AllTabs, TabOption, TabType } from "../types/TabOption";
|
|
|
import Browser from "./Browser";
|
|
|
import CodeEditor from "./CodeEditor";
|
|
|
@@ -12,7 +16,18 @@ import Planner from "./Planner";
|
|
|
|
|
|
function Workspace() {
|
|
|
const { t } = useTranslation();
|
|
|
+ const plan = useSelector((state: RootState) => state.plan.plan);
|
|
|
+ const code = useSelector((state: RootState) => state.code.code);
|
|
|
+ const screenshotSrc = useSelector(
|
|
|
+ (state: RootState) => state.browser.screenshotSrc,
|
|
|
+ );
|
|
|
+
|
|
|
const [activeTab, setActiveTab] = useState<TabType>(TabOption.CODE);
|
|
|
+ const [changes, setChanges] = useState<Record<TabType, boolean>>({
|
|
|
+ [TabOption.PLANNER]: false,
|
|
|
+ [TabOption.CODE]: false,
|
|
|
+ [TabOption.BROWSER]: false,
|
|
|
+ });
|
|
|
|
|
|
const tabData = useMemo(
|
|
|
() => ({
|
|
|
@@ -35,6 +50,30 @@ function Workspace() {
|
|
|
[t],
|
|
|
);
|
|
|
|
|
|
+ useEffect(() => {
|
|
|
+ if (activeTab !== TabOption.PLANNER && plan.mainGoal !== undefined) {
|
|
|
+ setChanges((prev) => ({ ...prev, [TabOption.PLANNER]: true }));
|
|
|
+ }
|
|
|
+ // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
+ }, [plan]);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (activeTab !== TabOption.CODE && code !== initialCodeState.code) {
|
|
|
+ setChanges((prev) => ({ ...prev, [TabOption.CODE]: true }));
|
|
|
+ }
|
|
|
+ // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
+ }, [plan]);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (
|
|
|
+ activeTab !== TabOption.BROWSER &&
|
|
|
+ screenshotSrc !== initialBrowserState.screenshotSrc
|
|
|
+ ) {
|
|
|
+ setChanges((prev) => ({ ...prev, [TabOption.BROWSER]: true }));
|
|
|
+ }
|
|
|
+ // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
+ }, [screenshotSrc]);
|
|
|
+
|
|
|
return (
|
|
|
<div className="flex flex-col min-h-0 grow">
|
|
|
<div
|
|
|
@@ -52,6 +91,7 @@ function Workspace() {
|
|
|
}}
|
|
|
size="lg"
|
|
|
onSelectionChange={(v) => {
|
|
|
+ setChanges((prev) => ({ ...prev, [v as TabType]: false }));
|
|
|
setActiveTab(v as TabType);
|
|
|
}}
|
|
|
>
|
|
|
@@ -63,6 +103,9 @@ function Workspace() {
|
|
|
<div className="flex grow items-center gap-2 justify-center text-xs">
|
|
|
{tabData[tab].icon}
|
|
|
<span>{tabData[tab].name}</span>
|
|
|
+ {changes[tab] && (
|
|
|
+ <div className="w-2 h-2 rounded-full animate-pulse bg-blue-500" />
|
|
|
+ )}
|
|
|
</div>
|
|
|
}
|
|
|
/>
|