diff --git a/servers/nextjs/app/(presentation-generator)/outline/hooks/useOutlineManagement.ts b/servers/nextjs/app/(presentation-generator)/outline/hooks/useOutlineManagement.ts
index 774b459e..b91c3d6e 100644
--- a/servers/nextjs/app/(presentation-generator)/outline/hooks/useOutlineManagement.ts
+++ b/servers/nextjs/app/(presentation-generator)/outline/hooks/useOutlineManagement.ts
@@ -11,12 +11,16 @@ export const useOutlineManagement = (outlines: { content: string }[] | null) =>
if (!active || !over || !outlines) return;
- if (active.id !== over.id) {
- const oldIndex = outlines.findIndex((item) => item.content === active.id);
- const newIndex = outlines.findIndex((item) => item.content === over.id);
- const reorderedArray = arrayMove(outlines, oldIndex, newIndex);
- dispatch(setOutlines(reorderedArray));
- }
+ if (active.id === over.id) return;
+
+ const oldIndex = Number(String(active.id).replace("slide-", ""));
+ const newIndex = Number(String(over.id).replace("slide-", ""));
+
+ if (Number.isNaN(oldIndex) || Number.isNaN(newIndex)) return;
+ if (oldIndex < 0 || newIndex < 0 || oldIndex >= outlines.length || newIndex >= outlines.length) return;
+
+ const reorderedArray = arrayMove(outlines, oldIndex, newIndex);
+ dispatch(setOutlines(reorderedArray));
}, [outlines, dispatch]);
const handleAddSlide = useCallback(() => {
diff --git a/servers/nextjs/app/(presentation-generator)/upload/components/AdvanceSettings.tsx b/servers/nextjs/app/(presentation-generator)/upload/components/AdvanceSettings.tsx
new file mode 100644
index 00000000..bd709a5c
--- /dev/null
+++ b/servers/nextjs/app/(presentation-generator)/upload/components/AdvanceSettings.tsx
@@ -0,0 +1,172 @@
+import ToolTip from '@/components/ToolTip'
+import { Button } from '@/components/ui/button'
+import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
+import { Switch } from '@/components/ui/switch'
+import { Textarea } from '@/components/ui/textarea'
+import { SlidersHorizontal } from 'lucide-react'
+import React, { useState } from 'react'
+import { PresentationConfig, ToneType, VerbosityType } from '../type'
+
+
+interface ConfigurationSelectsProps {
+ config: PresentationConfig;
+ onConfigChange: (key: keyof PresentationConfig, value: any) => void;
+}
+const AdvanceSettings = ({ config, onConfigChange }: ConfigurationSelectsProps) => {
+
+ const [openAdvanced, setOpenAdvanced] = useState(false);
+
+ const [advancedDraft, setAdvancedDraft] = useState({
+ tone: config.tone,
+ verbosity: config.verbosity,
+ instructions: config.instructions,
+ includeTableOfContents: config.includeTableOfContents,
+ includeTitleSlide: config.includeTitleSlide,
+ webSearch: config.webSearch,
+ });
+
+ const handleOpenAdvancedChange = (open: boolean) => {
+ if (open) {
+ setAdvancedDraft({
+ tone: config.tone,
+ verbosity: config.verbosity,
+ instructions: config.instructions,
+ includeTableOfContents: config.includeTableOfContents,
+ includeTitleSlide: config.includeTitleSlide,
+ webSearch: config.webSearch,
+ });
+ }
+ setOpenAdvanced(open);
+ };
+
+ const handleSaveAdvanced = () => {
+ onConfigChange("tone", advancedDraft.tone);
+ onConfigChange("verbosity", advancedDraft.verbosity);
+ onConfigChange("instructions", advancedDraft.instructions);
+ onConfigChange("includeTableOfContents", advancedDraft.includeTableOfContents);
+ onConfigChange("includeTitleSlide", advancedDraft.includeTitleSlide);
+ onConfigChange("webSearch", advancedDraft.webSearch);
+ setOpenAdvanced(false);
+ };
+ return (
+
+
+
+
+
+
+ )
+}
+
+export default AdvanceSettings
diff --git a/servers/nextjs/app/(presentation-generator)/upload/components/ConfigurationSelects.tsx b/servers/nextjs/app/(presentation-generator)/upload/components/ConfigurationSelects.tsx
deleted file mode 100644
index 618f7eaa..00000000
--- a/servers/nextjs/app/(presentation-generator)/upload/components/ConfigurationSelects.tsx
+++ /dev/null
@@ -1,364 +0,0 @@
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select";
-import { LanguageType, PresentationConfig, ToneType, VerbosityType } from "../type";
-import { useState } from "react";
-import { Check, ChevronsUpDown, SlidersHorizontal } from "lucide-react";
-import { Button } from "@/components/ui/button";
-import {
- Command,
- CommandEmpty,
- CommandGroup,
- CommandInput,
- CommandItem,
- CommandList,
-} from "@/components/ui/command";
-import {
- Popover,
- PopoverContent,
- PopoverTrigger,
-} from "@/components/ui/popover";
-import { cn } from "@/lib/utils";
-import { Input } from "@/components/ui/input";
-import { Switch } from "@/components/ui/switch";
-import { Textarea } from "@/components/ui/textarea";
-import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
-import ToolTip from "@/components/ToolTip";
-
-// Types
-interface ConfigurationSelectsProps {
- config: PresentationConfig;
- onConfigChange: (key: keyof PresentationConfig, value: any) => void;
-}
-
-type SlideOption = "5" | "8" | "9" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20";
-
-// Constants
-const SLIDE_OPTIONS: SlideOption[] = ["5", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20"];
-
-/**
- * Renders a select component for slide count
- */
-const SlideCountSelect: React.FC<{
- value: string | null;
- onValueChange: (value: string) => void;
-}> = ({ value, onValueChange }) => {
- const [customInput, setCustomInput] = useState(
- value && !SLIDE_OPTIONS.includes(value as SlideOption) ? value : ""
- );
-
- const sanitizeToPositiveInteger = (raw: string): string => {
- const digitsOnly = raw.replace(/\D+/g, "");
- if (!digitsOnly) return "";
- // Remove leading zeros
- const noLeadingZeros = digitsOnly.replace(/^0+/, "");
- return noLeadingZeros;
- };
-
- const applyCustomValue = () => {
- const sanitized = sanitizeToPositiveInteger(customInput);
- if (sanitized && Number(sanitized) > 0) {
- onValueChange(sanitized);
- }
- };
-
- return (
-
- );
-};
-
-/**
- * Renders a language selection component with search functionality
- */
-const LanguageSelect: React.FC<{
- value: string | null;
- onValueChange: (value: string) => void;
- open: boolean;
- onOpenChange: (open: boolean) => void;
-}> = ({ value, onValueChange, open, onOpenChange }) => (
-
-
-
-
-
-
-
-
- No language found.
-
- {Object.values(LanguageType).map((language) => (
- {
- onValueChange(currentValue);
- onOpenChange(false);
- }}
- className="font-instrument_sans"
- >
-
- {language}
-
- ))}
-
-
-
-
-
-);
-
-export function ConfigurationSelects({
- config,
- onConfigChange,
-}: ConfigurationSelectsProps) {
- const [openLanguage, setOpenLanguage] = useState(false);
- const [openAdvanced, setOpenAdvanced] = useState(false);
-
- const [advancedDraft, setAdvancedDraft] = useState({
- tone: config.tone,
- verbosity: config.verbosity,
- instructions: config.instructions,
- includeTableOfContents: config.includeTableOfContents,
- includeTitleSlide: config.includeTitleSlide,
- webSearch: config.webSearch,
- });
-
- const handleOpenAdvancedChange = (open: boolean) => {
- if (open) {
- setAdvancedDraft({
- tone: config.tone,
- verbosity: config.verbosity,
- instructions: config.instructions,
- includeTableOfContents: config.includeTableOfContents,
- includeTitleSlide: config.includeTitleSlide,
- webSearch: config.webSearch,
- });
- }
- setOpenAdvanced(open);
- };
-
- const handleSaveAdvanced = () => {
- onConfigChange("tone", advancedDraft.tone);
- onConfigChange("verbosity", advancedDraft.verbosity);
- onConfigChange("instructions", advancedDraft.instructions);
- onConfigChange("includeTableOfContents", advancedDraft.includeTableOfContents);
- onConfigChange("includeTitleSlide", advancedDraft.includeTitleSlide);
- onConfigChange("webSearch", advancedDraft.webSearch);
- setOpenAdvanced(false);
- };
-
- return (
-
-
onConfigChange("slides", value)}
- />
- onConfigChange("language", value)}
- open={openLanguage}
- onOpenChange={setOpenLanguage}
- />
-
-
-
-
-
-
-
- );
-}
diff --git a/servers/nextjs/app/(presentation-generator)/upload/components/LanguageSelector.tsx b/servers/nextjs/app/(presentation-generator)/upload/components/LanguageSelector.tsx
new file mode 100644
index 00000000..18365e60
--- /dev/null
+++ b/servers/nextjs/app/(presentation-generator)/upload/components/LanguageSelector.tsx
@@ -0,0 +1,69 @@
+import { Button } from '@/components/ui/button';
+import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from '@/components/ui/command';
+import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
+
+import { Check, ChevronDown } from 'lucide-react';
+import React, { useState } from 'react'
+import { LanguageType } from '../type';
+import { cn } from '@/lib/utils';
+
+
+export const LanguageSelector: React.FC<{
+ value: string | null;
+ onValueChange: (value: string) => void;
+
+}> = ({ value, onValueChange }) => {
+ const [openLanguage, setOpenLanguage] = useState(false);
+ return (
+
+
+
+
+
+
+
+
+ No language found.
+
+ {Object.values(LanguageType).map((language) => (
+ {
+ onValueChange(currentValue);
+ setOpenLanguage(false);
+ }}
+ className="font-instrument_sans"
+ >
+
+ {language}
+
+ ))}
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/servers/nextjs/app/(presentation-generator)/upload/components/NumberOfSlide.tsx b/servers/nextjs/app/(presentation-generator)/upload/components/NumberOfSlide.tsx
new file mode 100644
index 00000000..2affd975
--- /dev/null
+++ b/servers/nextjs/app/(presentation-generator)/upload/components/NumberOfSlide.tsx
@@ -0,0 +1,90 @@
+import { Input } from '@/components/ui/input';
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
+import React, { useState } from 'react'
+
+const SLIDE_OPTIONS: string[] = ["5", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20"];
+
+const NumberOfSlide = ({ value, onValueChange }: { value: string, onValueChange: (value: string) => void }) => {
+ const [customInput, setCustomInput] = useState(
+ value && !SLIDE_OPTIONS.includes(value) ? value : ""
+ );
+
+ const sanitizeToPositiveInteger = (raw: string): string => {
+ const digitsOnly = raw.replace(/\D+/g, "");
+ if (!digitsOnly) return "";
+ // Remove leading zeros
+ const noLeadingZeros = digitsOnly.replace(/^0+/, "");
+ return noLeadingZeros;
+ };
+
+ const applyCustomValue = () => {
+ const sanitized = sanitizeToPositiveInteger(customInput);
+ if (sanitized && Number(sanitized) > 0) {
+ onValueChange(sanitized);
+ }
+ };
+ return (
+
+ )
+}
+
+export default NumberOfSlide
diff --git a/servers/nextjs/app/(presentation-generator)/upload/components/PromptInput.tsx b/servers/nextjs/app/(presentation-generator)/upload/components/PromptInput.tsx
index 9eccb815..ad28e4ce 100644
--- a/servers/nextjs/app/(presentation-generator)/upload/components/PromptInput.tsx
+++ b/servers/nextjs/app/(presentation-generator)/upload/components/PromptInput.tsx
@@ -13,30 +13,30 @@ export function PromptInput({
onChange,
}: PromptInputProps) {
- const [showHint, setShowHint] = useState(false);
- const handleChange = (value: string) => {
- setShowHint(value.length > 0);
- onChange(value);
- };
+
return (
-
-
-
-
- Provide specific details about your presentation needs (e.g., topic,
- style, key points) for more accurate results
-
-
+
+
+