diff --git a/src/components/features/playground/workspace/editor/components/copy-button.tsx b/src/components/features/playground/workspace/editor/components/copy-button.tsx
deleted file mode 100644
index b229c86..0000000
--- a/src/components/features/playground/workspace/editor/components/copy-button.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-"use client";
-
-import {
- Tooltip,
- TooltipContent,
- TooltipProvider,
- TooltipTrigger,
-} from "@/components/ui/tooltip";
-import { cn } from "@/lib/utils";
-import { useState } from "react";
-import { Check, Copy } from "lucide-react";
-import { useTranslations } from "next-intl";
-import { Button } from "@/components/ui/button";
-import { useProblem } from "@/hooks/use-problem";
-
-export function CopyButton() {
- const { editor } = useProblem();
- const [copied, setCopied] = useState(false);
- const t = useTranslations("WorkspaceEditorHeader.CopyButton");
-
- const handleCopy = async () => {
- try {
- await navigator.clipboard.writeText(editor?.getValue() || "");
- setCopied(true);
- setTimeout(() => setCopied(false), 1500);
- } catch (err) {
- console.error("Failed to copy text: ", err);
- }
- };
-
- return (
-
-
-
-
-
-
- {t("TooltipContent")}
-
-
-
- );
-}
diff --git a/src/components/features/playground/workspace/editor/components/format-button.tsx b/src/components/features/playground/workspace/editor/components/format-button.tsx
deleted file mode 100644
index ab934b6..0000000
--- a/src/components/features/playground/workspace/editor/components/format-button.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-"use client";
-
-import {
- Tooltip,
- TooltipContent,
- TooltipProvider,
- TooltipTrigger,
-} from "@/components/ui/tooltip";
-import { Paintbrush } from "lucide-react";
-import { useTranslations } from "next-intl";
-import { Button } from "@/components/ui/button";
-import { useProblem } from "@/hooks/use-problem";
-
-export function FormatButton() {
- const { editor } = useProblem();
- const t = useTranslations("WorkspaceEditorHeader.FormatButton");
-
- return (
-
-
-
-
-
-
- {t("TooltipContent")}
-
-
-
- );
-}
diff --git a/src/components/features/playground/workspace/editor/components/redo-button.tsx b/src/components/features/playground/workspace/editor/components/redo-button.tsx
deleted file mode 100644
index 92bcd63..0000000
--- a/src/components/features/playground/workspace/editor/components/redo-button.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-"use client";
-
-import {
- Tooltip,
- TooltipContent,
- TooltipProvider,
- TooltipTrigger,
-} from "@/components/ui/tooltip";
-import { Redo2 } from "lucide-react";
-import { useTranslations } from "next-intl";
-import { Button } from "@/components/ui/button";
-import { useProblem } from "@/hooks/use-problem";
-
-export function RedoButton() {
- const { editor } = useProblem();
- const t = useTranslations("WorkspaceEditorHeader.RedoButton");
-
- return (
-
-
-
-
-
-
- {t("TooltipContent")}
-
-
-
- );
-}
diff --git a/src/components/features/playground/workspace/editor/components/reset-button.tsx b/src/components/features/playground/workspace/editor/components/reset-button.tsx
deleted file mode 100644
index 4f4b5d8..0000000
--- a/src/components/features/playground/workspace/editor/components/reset-button.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-"use client";
-
-import {
- Tooltip,
- TooltipContent,
- TooltipProvider,
- TooltipTrigger,
-} from "@/components/ui/tooltip";
-import { RotateCcw } from "lucide-react";
-import { useTranslations } from "next-intl";
-import { Button } from "@/components/ui/button";
-import { useProblem } from "@/hooks/use-problem";
-
-export function ResetButton() {
- const { editor, currentTemplate } = useProblem();
- const t = useTranslations("WorkspaceEditorHeader.ResetButton");
-
- const handleReset = () => {
- if (editor) {
- const model = editor.getModel();
- if (model) {
- const fullRange = model.getFullModelRange();
- editor.pushUndoStop();
- editor.executeEdits("reset-code", [
- {
- range: fullRange,
- text: currentTemplate,
- forceMoveMarkers: true,
- },
- ]);
- editor.pushUndoStop();
- }
- }
- };
-
- return (
-
-
-
-
-
-
- {t("TooltipContent")}
-
-
-
- );
-}
diff --git a/src/components/features/playground/workspace/editor/components/undo-button.tsx b/src/components/features/playground/workspace/editor/components/undo-button.tsx
deleted file mode 100644
index d7ec502..0000000
--- a/src/components/features/playground/workspace/editor/components/undo-button.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-"use client";
-
-import {
- Tooltip,
- TooltipContent,
- TooltipProvider,
- TooltipTrigger,
-} from "@/components/ui/tooltip";
-import { Undo2 } from "lucide-react";
-import { useTranslations } from "next-intl";
-import { Button } from "@/components/ui/button";
-import { useProblem } from "@/hooks/use-problem";
-
-export function UndoButton() {
- const { editor } = useProblem();
- const t = useTranslations("WorkspaceEditorHeader.UndoButton");
-
- return (
-
-
-
-
-
-
- {t("TooltipContent")}
-
-
-
- );
-}
diff --git a/src/features/problems/code/components/toolbar/actions/copy-button.tsx b/src/features/problems/code/components/toolbar/actions/copy-button.tsx
new file mode 100644
index 0000000..3c97762
--- /dev/null
+++ b/src/features/problems/code/components/toolbar/actions/copy-button.tsx
@@ -0,0 +1,56 @@
+"use client";
+
+import { cn } from "@/lib/utils";
+import { useState } from "react";
+import { Check, Copy } from "lucide-react";
+import { useTranslations } from "next-intl";
+import { TooltipButton } from "@/components/tooltip-button";
+import { useProblemEditorActions } from "@/features/problems/code/hooks/use-problem-editor-actions";
+
+const CopyButton = () => {
+ const t = useTranslations("WorkspaceEditorHeader.CopyButton");
+ const [copied, setCopied] = useState(false);
+ const { canExecute, handleCopy } = useProblemEditorActions();
+
+ const handleClick = async () => {
+ const success = await handleCopy();
+ if (success) {
+ setCopied(true);
+ setTimeout(() => setCopied(false), 1500);
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+
+export { CopyButton };
diff --git a/src/features/problems/code/components/toolbar/actions/format-button.tsx b/src/features/problems/code/components/toolbar/actions/format-button.tsx
new file mode 100644
index 0000000..8add6e3
--- /dev/null
+++ b/src/features/problems/code/components/toolbar/actions/format-button.tsx
@@ -0,0 +1,24 @@
+"use client";
+
+import { Paintbrush } from "lucide-react";
+import { useTranslations } from "next-intl";
+import { TooltipButton } from "@/components/tooltip-button";
+import { useProblemEditorActions } from "@/features/problems/code/hooks/use-problem-editor-actions";
+
+const FormatButton = () => {
+ const t = useTranslations("WorkspaceEditorHeader.FormatButton");
+ const { canExecute, handleFormat } = useProblemEditorActions();
+
+ return (
+
+
+
+ );
+};
+
+export { FormatButton };
diff --git a/src/features/problems/code/components/toolbar/actions/redo-button.tsx b/src/features/problems/code/components/toolbar/actions/redo-button.tsx
new file mode 100644
index 0000000..af6411d
--- /dev/null
+++ b/src/features/problems/code/components/toolbar/actions/redo-button.tsx
@@ -0,0 +1,24 @@
+"use client";
+
+import { Redo2 } from "lucide-react";
+import { useTranslations } from "next-intl";
+import { TooltipButton } from "@/components/tooltip-button";
+import { useProblemEditorActions } from "@/features/problems/code/hooks/use-problem-editor-actions";
+
+const RedoButton = () => {
+ const t = useTranslations("WorkspaceEditorHeader.RedoButton");
+ const { canExecute, handleRedo } = useProblemEditorActions();
+
+ return (
+
+
+
+ );
+};
+
+export { RedoButton };
diff --git a/src/features/problems/code/components/toolbar/actions/reset-button.tsx b/src/features/problems/code/components/toolbar/actions/reset-button.tsx
new file mode 100644
index 0000000..7f5ed2a
--- /dev/null
+++ b/src/features/problems/code/components/toolbar/actions/reset-button.tsx
@@ -0,0 +1,43 @@
+"use client";
+
+import { useMemo } from "react";
+import { RotateCcw } from "lucide-react";
+import { useTranslations } from "next-intl";
+import type { Template } from "@/generated/client";
+import { TooltipButton } from "@/components/tooltip-button";
+import { useProblemEditorStore } from "@/stores/problem-editor-store";
+import { useProblemEditorActions } from "@/features/problems/code/hooks/use-problem-editor-actions";
+
+interface ResetButtonProps {
+ templates: Template[];
+}
+
+const ResetButton = ({ templates }: ResetButtonProps) => {
+ const t = useTranslations("WorkspaceEditorHeader.ResetButton");
+ const { language } = useProblemEditorStore();
+ const { canExecute, handleReset } = useProblemEditorActions();
+
+ const currentTemplate = useMemo(() => {
+ return (
+ templates.find((template) => template.language === language)?.template ??
+ ""
+ );
+ }, [language, templates]);
+
+ const handleClick = () => {
+ handleReset(currentTemplate);
+ };
+
+ return (
+
+
+
+ );
+};
+
+export { ResetButton };
diff --git a/src/features/problems/code/components/toolbar/actions/undo-button.tsx b/src/features/problems/code/components/toolbar/actions/undo-button.tsx
new file mode 100644
index 0000000..d10a579
--- /dev/null
+++ b/src/features/problems/code/components/toolbar/actions/undo-button.tsx
@@ -0,0 +1,24 @@
+"use client";
+
+import { Undo2 } from "lucide-react";
+import { useTranslations } from "next-intl";
+import { TooltipButton } from "@/components/tooltip-button";
+import { useProblemEditorActions } from "@/features/problems/code/hooks/use-problem-editor-actions";
+
+const UndoButton = () => {
+ const t = useTranslations("WorkspaceEditorHeader.UndoButton");
+ const { canExecute, handleUndo } = useProblemEditorActions();
+
+ return (
+
+
+
+ );
+};
+
+export { UndoButton };
diff --git a/src/features/problems/code/components/toolbar/index.ts b/src/features/problems/code/components/toolbar/index.ts
new file mode 100644
index 0000000..4ce7274
--- /dev/null
+++ b/src/features/problems/code/components/toolbar/index.ts
@@ -0,0 +1,5 @@
+export * from "./actions/copy-button";
+export * from "./actions/format-button";
+export * from "./actions/redo-button";
+export * from "./actions/reset-button";
+export * from "./actions/undo-button";
diff --git a/src/features/problems/code/hooks/use-problem-editor-actions.ts b/src/features/problems/code/hooks/use-problem-editor-actions.ts
new file mode 100644
index 0000000..b17cd33
--- /dev/null
+++ b/src/features/problems/code/hooks/use-problem-editor-actions.ts
@@ -0,0 +1,55 @@
+import { useCallback } from "react";
+import { useProblemEditorStore } from "@/stores/problem-editor-store";
+
+export const useProblemEditorActions = () => {
+ const { editor } = useProblemEditorStore();
+
+ const handleCopy = useCallback(async () => {
+ try {
+ await navigator.clipboard.writeText(editor?.getValue() || "");
+ return true;
+ } catch (error) {
+ console.error("Failed to copy text: ", error);
+ return false;
+ }
+ }, [editor]);
+
+ const handleFormat = useCallback(() => {
+ editor?.trigger("format", "editor.action.formatDocument", null);
+ }, [editor]);
+
+ const handleUndo = useCallback(() => {
+ editor?.trigger("undo", "undo", null);
+ }, [editor]);
+
+ const handleRedo = useCallback(() => {
+ editor?.trigger("redo", "redo", null);
+ }, [editor]);
+
+ const handleReset = useCallback((template: string) => {
+ if (!editor) return;
+
+ const model = editor.getModel();
+ if (!model) return;
+
+ const fullRange = model.getFullModelRange();
+ editor.pushUndoStop();
+ editor.executeEdits("reset-code", [
+ {
+ range: fullRange,
+ text: template,
+ forceMoveMarkers: true,
+ },
+ ]);
+ editor.pushUndoStop();
+ }, [editor]);
+
+ return {
+ handleCopy,
+ handleFormat,
+ handleUndo,
+ handleRedo,
+ handleReset,
+ canExecute: !!editor,
+ };
+};