Compare commits

...
Sign in to create a new pull request.

4 commits

Author SHA1 Message Date
shubham.goyal@brandtech.plus
d5bb04a837 fix download path 2026-05-17 20:35:21 +05:30
shubham.goyal@brandtech.plus
36ae0438a1 Merge branch 'main' of https://bitbucket.org/zlalani/ppt-tool 2026-05-17 20:08:17 +05:30
shubham.goyal@brandtech.plus
e054916f44 fix ppt download issue 2026-05-17 20:07:56 +05:30
Shubham Goyal
9917015456 Merged in fix/login-issue (pull request #1)
fix login issue and ppt outlines
2026-05-12 13:38:14 +00:00
4 changed files with 39 additions and 13 deletions

View file

@ -17,6 +17,7 @@ import {
PopoverTrigger, PopoverTrigger,
} from "@/components/ui/popover"; } from "@/components/ui/popover";
import { PresentationGenerationApi } from "../../services/api/presentation-generation"; import { PresentationGenerationApi } from "../../services/api/presentation-generation";
import { apiFetch, apiUrl } from "@/lib/apiFetch";
import { OverlayLoader } from "@/components/ui/overlay-loader"; import { OverlayLoader } from "@/components/ui/overlay-loader";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
@ -59,7 +60,7 @@ const Header = ({
const { onUndo, onRedo, canUndo, canRedo } = usePresentationUndoRedo(); const { onUndo, onRedo, canUndo, canRedo } = usePresentationUndoRedo();
const get_presentation_pptx_model = async (id: string): Promise<PptxPresentationModel> => { const get_presentation_pptx_model = async (id: string): Promise<PptxPresentationModel> => {
const response = await fetch(`/api/presentation_to_pptx_model?id=${id}`); const response = await apiFetch(`/api/presentation_to_pptx_model?id=${id}`);
const pptx_model = await response.json(); const pptx_model = await response.json();
return pptx_model; return pptx_model;
}; };
@ -104,7 +105,7 @@ const Header = ({
// Save the presentation data before exporting // Save the presentation data before exporting
await PresentationGenerationApi.updatePresentationContent(presentationData); await PresentationGenerationApi.updatePresentationContent(presentationData);
const response = await fetch('/api/export-as-pdf', { const response = await apiFetch('/api/export-as-pdf', {
method: 'POST', method: 'POST',
body: JSON.stringify({ body: JSON.stringify({
id: presentation_id, id: presentation_id,
@ -136,13 +137,14 @@ const Header = ({
router.push(`/presentation?id=${presentation_id}&stream=true`); router.push(`/presentation?id=${presentation_id}&stream=true`);
}; };
const downloadLink = (path: string) => { const downloadLink = (path: string) => {
const url = apiUrl(path);
// if we have popup access give direct download if not redirect to the path // if we have popup access give direct download if not redirect to the path
if (window.opener) { if (window.opener) {
window.open(path, '_blank'); window.open(url, '_blank');
} else { } else {
const link = document.createElement('a'); const link = document.createElement('a');
link.href = path; link.href = url;
link.download = path.split('/').pop() || 'download'; link.download = url.split('/').pop() || 'download';
document.body.appendChild(link); document.body.appendChild(link);
link.click(); link.click();
} }

View file

@ -35,7 +35,8 @@ export async function GET(request: NextRequest) {
try { try {
const id = await getPresentationId(request); const id = await getPresentationId(request);
[browser, page] = await getBrowserAndPage(id); const sessionToken = request.cookies.get("session_token")?.value;
[browser, page] = await getBrowserAndPage(id, sessionToken);
const screenshotsDir = getScreenshotsDir(); const screenshotsDir = getScreenshotsDir();
const { slides, speakerNotes } = await getSlidesAndSpeakerNotes(page); const { slides, speakerNotes } = await getSlidesAndSpeakerNotes(page);
@ -75,7 +76,10 @@ async function getPresentationId(request: NextRequest) {
return id; return id;
} }
async function getBrowserAndPage(id: string): Promise<[Browser, Page]> { async function getBrowserAndPage(
id: string,
sessionToken: string | undefined
): Promise<[Browser, Page]> {
const browser = await puppeteer.launch({ const browser = await puppeteer.launch({
executablePath: process.env.PUPPETEER_EXECUTABLE_PATH, executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,
headless: true, headless: true,
@ -99,10 +103,24 @@ async function getBrowserAndPage(id: string): Promise<[Browser, Page]> {
page.setDefaultNavigationTimeout(300000); page.setDefaultNavigationTimeout(300000);
page.setDefaultTimeout(300000); page.setDefaultTimeout(300000);
const baseUrl = process.env.PUPPETEER_BASE_URL || `http://localhost:${process.env.PORT || 3000}`; const baseUrl = process.env.PUPPETEER_BASE_URL || `http://localhost:${process.env.PORT || 3000}`;
await page.goto(`${baseUrl}/pdf-maker?id=${id}`, {
waitUntil: "networkidle0", if (sessionToken) {
timeout: 300000, await page.setCookie({
name: "session_token",
value: sessionToken,
url: baseUrl,
httpOnly: true,
});
}
await page.goto(`${baseUrl}/ppt-tool/pdf-maker?id=${id}`, {
waitUntil: "domcontentloaded",
timeout: 60000,
}); });
await page.waitForSelector(
"#presentation-slides-wrapper [data-speaker-note]",
{ timeout: 120000 }
);
return [browser, page]; return [browser, page];
} }

View file

@ -7,12 +7,18 @@
*/ */
const BASE_PATH = '/ppt-tool'; const BASE_PATH = '/ppt-tool';
const PREFIXED_PATHS = ['/api/', '/app_data/', '/static/'];
function needsBasePath(path: string): boolean {
return PREFIXED_PATHS.some((p) => path.startsWith(p));
}
export function apiFetch(path: string, init?: RequestInit): Promise<Response> { export function apiFetch(path: string, init?: RequestInit): Promise<Response> {
const url = path.startsWith('/api/') ? `${BASE_PATH}${path}` : path; const url = needsBasePath(path) ? `${BASE_PATH}${path}` : path;
return fetch(url, init); return fetch(url, init);
} }
/** Returns the full URL with basePath — use for EventSource and other non-fetch calls. */ /** Returns the full URL with basePath — use for EventSource and other non-fetch calls. */
export function apiUrl(path: string): string { export function apiUrl(path: string): string {
return path.startsWith('/api/') ? `${BASE_PATH}${path}` : path; return needsBasePath(path) ? `${BASE_PATH}${path}` : path;
} }

View file

@ -200,7 +200,7 @@ function convertToAutoShapeBox(element: ElementAttributes): PptxAutoShapeBoxMode
shadow, shadow,
position, position,
text_wrap: element.textWrap ?? true, text_wrap: element.textWrap ?? true,
border_radius: borderRadius || undefined, border_radius: borderRadius ? Math.round(borderRadius) : undefined,
paragraphs paragraphs
}; };
} }