diff --git a/servers/fastapi/api/main.py b/servers/fastapi/api/main.py index 5c8aaec5..93517b12 100644 --- a/servers/fastapi/api/main.py +++ b/servers/fastapi/api/main.py @@ -4,7 +4,7 @@ from fastapi.staticfiles import StaticFiles from api.lifespan import app_lifespan from api.middlewares import UserConfigEnvUpdateMiddleware from api.v1.ppt.router import API_V1_PPT_ROUTER -from utils.asset_directory_utils import get_exports_directory, get_images_directory +from utils.asset_directory_utils import get_exports_directory, get_images_directory, get_uploads_directory app = FastAPI(lifespan=app_lifespan) @@ -25,6 +25,11 @@ app.mount( StaticFiles(directory=get_exports_directory()), name="app_data/exports", ) +app.mount( + "/app_data/uploads", + StaticFiles(directory=get_uploads_directory()), + name="app_data/uploads", +) # Middlewares diff --git a/servers/fastapi/utils/asset_directory_utils.py b/servers/fastapi/utils/asset_directory_utils.py index 13a0673c..a88196c1 100644 --- a/servers/fastapi/utils/asset_directory_utils.py +++ b/servers/fastapi/utils/asset_directory_utils.py @@ -12,3 +12,8 @@ def get_exports_directory(): export_directory = os.path.join(get_app_data_directory_env(), "exports") os.makedirs(export_directory, exist_ok=True) return export_directory + +def get_uploads_directory(): + uploads_directory = os.path.join(get_app_data_directory_env(), "uploads") + os.makedirs(uploads_directory, exist_ok=True) + return uploads_directory diff --git a/servers/nextjs/app/(presentation-generator)/presentation/components/Header.tsx b/servers/nextjs/app/(presentation-generator)/presentation/components/Header.tsx index c198445b..12ec7a05 100644 --- a/servers/nextjs/app/(presentation-generator)/presentation/components/Header.tsx +++ b/servers/nextjs/app/(presentation-generator)/presentation/components/Header.tsx @@ -22,7 +22,6 @@ import Link from "next/link"; import { RootState } from "@/store/store"; import { toast } from "sonner"; -import Modal from "./Modal"; import Announcement from "@/components/Announcement"; import { getStaticFileUrl } from "../../utils/others"; @@ -41,13 +40,10 @@ const Header = ({ const [showLoader, setShowLoader] = useState(false); const router = useRouter(); - const [showDownloadModal, setShowDownloadModal] = useState(false); - const [downloadPath, setDownloadPath] = useState(""); const { presentationData, isStreaming } = useSelector( (state: RootState) => state.presentationGeneration ); - const dispatch = useDispatch(); const get_presentation_pptx_model = async (id: string): Promise => { const response = await fetch(`/api/presentation_to_pptx_model?id=${id}`); @@ -101,8 +97,7 @@ const Header = ({ if (response.ok) { const { path: pdfPath } = await response.json(); - const staticFileUrl = getStaticFileUrl(pdfPath); - window.open(staticFileUrl, '_blank'); + window.open(pdfPath, '_blank'); } else { throw new Error("Failed to export PDF"); } @@ -210,17 +205,7 @@ const Header = ({ - {/* Download Modal */} - setShowDownloadModal(false)} - title="File Downloaded" - > -
-

Your file is saved at:

-

{downloadPath}

-
-
+ ); }; diff --git a/servers/nextjs/app/api/export-as-pdf/route.ts b/servers/nextjs/app/api/export-as-pdf/route.ts index 30393da6..77798b8e 100644 --- a/servers/nextjs/app/api/export-as-pdf/route.ts +++ b/servers/nextjs/app/api/export-as-pdf/route.ts @@ -8,6 +8,7 @@ import { NextResponse, NextRequest } from 'next/server'; export async function POST(req: NextRequest) { const { id, title } = await req.json(); + console.log('path', process.env.APP_DATA_DIRECTORY); if (!id) { return NextResponse.json({ error: "Missing Presentation ID" }, { status: 400 }); } @@ -26,7 +27,8 @@ export async function POST(req: NextRequest) { }); browser.close(); const sanitizedTitle = sanitizeFilename(title); - const destinationPath = path.join(process.env.APP_DATA_DIRECTORY!, `${sanitizedTitle}.pdf`); + const destinationPath = path.join(process.env.APP_DATA_DIRECTORY!,'exports', `${sanitizedTitle}.pdf`); + console.log('destinationPath', destinationPath); await fs.promises.writeFile(destinationPath, pdfBuffer); return NextResponse.json({ diff --git a/servers/nextjs/app/api/upload-image/route.ts b/servers/nextjs/app/api/upload-image/route.ts index 24ab96e1..8504f168 100644 --- a/servers/nextjs/app/api/upload-image/route.ts +++ b/servers/nextjs/app/api/upload-image/route.ts @@ -22,14 +22,13 @@ export async function POST(request: NextRequest) { const buffer = Buffer.from(bytes); // Create uploads directory if it doesn't exist - const uploadsDir = path.join(userDataDir, "images"); + const uploadsDir = path.join(userDataDir, "uploads"); fs.mkdirSync(uploadsDir, { recursive: true }); - console.log("uploadsDir", uploadsDir); + // Generate unique filename const filename = `${crypto.randomBytes(16).toString("hex")}.png`; const filePath = path.join(uploadsDir, filename); - console.log("filePath", filePath); // Write file to disk fs.writeFileSync(filePath, buffer); diff --git a/servers/nextjs/components/ui/sidebar.tsx b/servers/nextjs/components/ui/sidebar.tsx deleted file mode 100644 index 5e5b3384..00000000 --- a/servers/nextjs/components/ui/sidebar.tsx +++ /dev/null @@ -1,772 +0,0 @@ -"use client" - -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { VariantProps, cva } from "class-variance-authority" -import { useIsMobile } from "@/hooks/use-mobile" -import { cn } from "@/lib/utils" -import { Button } from "@/components/ui/button" -import { Input } from "@/components/ui/input" -import { Separator } from "@/components/ui/separator" -import { - Sheet, - SheetContent, - SheetDescription, - SheetHeader, - SheetTitle, -} from "@/components/ui/sheet" -import { Skeleton } from "@/components/ui/skeleton" -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip" -import { ViewVerticalIcon } from "@radix-ui/react-icons" - -const SIDEBAR_COOKIE_NAME = "sidebar_state" -const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7 -const SIDEBAR_WIDTH = "16rem" -const SIDEBAR_WIDTH_MOBILE = "18rem" -const SIDEBAR_WIDTH_ICON = "3rem" -const SIDEBAR_KEYBOARD_SHORTCUT = "b" - -type SidebarContextProps = { - state: "expanded" | "collapsed" - open: boolean - setOpen: (open: boolean) => void - openMobile: boolean - setOpenMobile: (open: boolean) => void - isMobile: boolean - toggleSidebar: () => void -} - -const SidebarContext = React.createContext(null) - -function useSidebar() { - const context = React.useContext(SidebarContext) - if (!context) { - throw new Error("useSidebar must be used within a SidebarProvider.") - } - - return context -} - -const SidebarProvider = React.forwardRef< - HTMLDivElement, - React.ComponentProps<"div"> & { - defaultOpen?: boolean - open?: boolean - onOpenChange?: (open: boolean) => void - } ->( - ( - { - defaultOpen = true, - open: openProp, - onOpenChange: setOpenProp, - className, - style, - children, - ...props - }, - ref - ) => { - const isMobile = useIsMobile() - const [openMobile, setOpenMobile] = React.useState(false) - - // This is the internal state of the sidebar. - // We use openProp and setOpenProp for control from outside the component. - const [_open, _setOpen] = React.useState(defaultOpen) - const open = openProp ?? _open - const setOpen = React.useCallback( - (value: boolean | ((value: boolean) => boolean)) => { - const openState = typeof value === "function" ? value(open) : value - if (setOpenProp) { - setOpenProp(openState) - } else { - _setOpen(openState) - } - - // This sets the cookie to keep the sidebar state. - document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}` - }, - [setOpenProp, open] - ) - - // Helper to toggle the sidebar. - const toggleSidebar = React.useCallback(() => { - return isMobile - ? setOpenMobile((open) => !open) - : setOpen((open) => !open) - }, [isMobile, setOpen, setOpenMobile]) - - // Adds a keyboard shortcut to toggle the sidebar. - React.useEffect(() => { - const handleKeyDown = (event: KeyboardEvent) => { - if ( - event.key === SIDEBAR_KEYBOARD_SHORTCUT && - (event.metaKey || event.ctrlKey) - ) { - event.preventDefault() - toggleSidebar() - } - } - - window.addEventListener("keydown", handleKeyDown) - return () => window.removeEventListener("keydown", handleKeyDown) - }, [toggleSidebar]) - - // We add a state so that we can do data-state="expanded" or "collapsed". - // This makes it easier to style the sidebar with Tailwind classes. - const state = open ? "expanded" : "collapsed" - - const contextValue = React.useMemo( - () => ({ - state, - open, - setOpen, - isMobile, - openMobile, - setOpenMobile, - toggleSidebar, - }), - [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar] - ) - - return ( - - -
- {children} -
-
-
- ) - } -) -SidebarProvider.displayName = "SidebarProvider" - -const Sidebar = React.forwardRef< - HTMLDivElement, - React.ComponentProps<"div"> & { - side?: "left" | "right" - variant?: "sidebar" | "floating" | "inset" - collapsible?: "offcanvas" | "icon" | "none" - } ->( - ( - { - side = "left", - variant = "sidebar", - collapsible = "offcanvas", - className, - children, - ...props - }, - ref - ) => { - const { isMobile, state, openMobile, setOpenMobile } = useSidebar() - - if (collapsible === "none") { - return ( -
- {children} -
- ) - } - - if (isMobile) { - return ( - - - - Sidebar - Displays the mobile sidebar. - -
{children}
-
-
- ) - } - - return ( -
- {/* This is what handles the sidebar gap on desktop */} -
- -
- ) - } -) -Sidebar.displayName = "Sidebar" - -const SidebarTrigger = React.forwardRef< - React.ElementRef, - React.ComponentProps ->(({ className, onClick, ...props }, ref) => { - const { toggleSidebar } = useSidebar() - - return ( - - ) -}) -SidebarTrigger.displayName = "SidebarTrigger" - -const SidebarRail = React.forwardRef< - HTMLButtonElement, - React.ComponentProps<"button"> ->(({ className, ...props }, ref) => { - const { toggleSidebar } = useSidebar() - - return ( -