feat(nextjs): Slide edit using prompt added

This commit is contained in:
shiva raj badu 2025-07-21 03:14:29 +05:45
parent f10eb5d7a6
commit dece7399d4
No known key found for this signature in database
8 changed files with 22 additions and 29 deletions

View file

@ -42,11 +42,11 @@ const EditableLayoutWrapper: React.FC<EditableLayoutWrapperProps> = ({
const matches: { path: string; type: 'image' | 'icon'; data: any }[] = [];
// Check current level for __image_url__ or __icon_url__
if (data.__image_url__ && isMatchingUrl(data.__image_url__, targetUrl)) {
if (data.__image_url__ && targetUrl.includes(data.__image_url__)) {
matches.push({ path, type: 'image', data });
}
if (data.__icon_url__ && isMatchingUrl(data.__icon_url__, targetUrl)) {
if (data.__icon_url__ && targetUrl.includes(data.__icon_url__)) {
matches.push({ path, type: 'icon', data });
}
@ -109,14 +109,16 @@ const EditableLayoutWrapper: React.FC<EditableLayoutWrapperProps> = ({
* Checks if two URLs match using various comparison strategies
*/
const isMatchingUrl = (url1: string, url2: string): boolean => {
console.log('url1', url1);
console.log('url2', url2);
if (!url1 || !url2) return false;
// Direct match
if (url1 === url2) return true;
// Remove protocol and domain differences
const cleanUrl1 = url1.replace(/^https?:\/\/[^\/]+/, '').replace(/^\/+/, '');
const cleanUrl2 = url2.replace(/^https?:\/\/[^\/]+/, '').replace(/^\/+/, '');
const cleanUrl1 = url1 && url1.replace(/^https?:\/\/[^\/]+/, '').replace(/^\/+/, '');
const cleanUrl2 = url2 && url2.replace(/^https?:\/\/[^\/]+/, '').replace(/^\/+/, '');
if (cleanUrl1 === cleanUrl2) return true;
@ -304,7 +306,7 @@ const EditableLayoutWrapper: React.FC<EditableLayoutWrapperProps> = ({
imageUrl: newImageUrl,
prompt: prompt || activeEditor.data?.__image_prompt__ || ''
}));
setActiveEditor(null);
}
};
/**
@ -323,6 +325,8 @@ const EditableLayoutWrapper: React.FC<EditableLayoutWrapperProps> = ({
query: query || activeEditor.data?.__icon_query__ || ''
}));
}
};
@ -341,7 +345,6 @@ const EditableLayoutWrapper: React.FC<EditableLayoutWrapperProps> = ({
onClose={handleEditorClose}
onImageChange={handleImageChange}
>
</ImageEditor>
)}

View file

@ -5,9 +5,6 @@ import ReactDOM from 'react-dom/client';
import TiptapText from './TiptapText';
interface TiptapTextReplacerProps {
layout: React.ComponentType<{
data: any;
}>;
children: ReactNode;
slideData?: any;
slideIndex?: number;
@ -18,11 +15,11 @@ interface TiptapTextReplacerProps {
const TiptapTextReplacer: React.FC<TiptapTextReplacerProps> = ({
children,
slideData,
layout,
slideIndex,
onContentChange = () => { },
isEditMode = true
}) => {
const containerRef = useRef<HTMLDivElement>(null);
const [processedElements, setProcessedElements] = useState(new Set<HTMLElement>());
useEffect(() => {
@ -107,7 +104,6 @@ const TiptapTextReplacer: React.FC<TiptapTextReplacerProps> = ({
const root = ReactDOM.createRoot(tiptapContainer);
root.render(
<TiptapText
key={trimmedText}
content={trimmedText}
onContentChange={(content: string) => {
if (dataPath && onContentChange) {
@ -261,7 +257,7 @@ const TiptapTextReplacer: React.FC<TiptapTextReplacerProps> = ({
}, [slideData, isEditMode, slideIndex]);
return (
<div ref={containerRef} className="tiptap-text-replacer">
<div ref={containerRef} key={slideData} className="tiptap-text-replacer">
{children}
</div>
);

View file

@ -55,13 +55,11 @@ export const useGroupLayouts = () => {
isEditMode={isEditMode}
>
<TiptapTextReplacer
key={slide.id}
slideData={slide.content}
slideIndex={slide.index}
isEditMode={isEditMode}
layout={Layout}
onContentChange={(content: string, dataPath: string, slideIndex?: number) => {
// Dispatch Redux action to update slide content
if (dataPath && slideIndex !== undefined) {
dispatch(updateSlideContent({
@ -72,12 +70,12 @@ export const useGroupLayouts = () => {
}
}}
>
<Layout data={slide.content} />
<Layout key={`layout-${slide.index}-${JSON.stringify(slide.content)}`} data={slide.content} />
</TiptapTextReplacer>
</EditableLayoutWrapper>
);
}
return <Layout data={slide.content} />;
return <Layout key={`layout-${slide.index}-${JSON.stringify(slide.content)}`} data={slide.content} />;
};
}, [getGroupLayout, dispatch]);

View file

@ -26,7 +26,7 @@ const GroupLayouts: React.FC<GroupLayoutsProps> = ({ group, onSelectLayoutGroup,
)}
<div className="mb-3">
<h6 className="text-base font-medium text-gray-900 mb-1">
<h6 className="text-base capitalize font-medium text-gray-900 mb-1">
{group.name}
</h6>
<p className="text-sm text-gray-600">

View file

@ -45,7 +45,6 @@ const PresentationPage = ({ presentation_id }: { presentation_id: string }) => {
setContentLoading(false);
}
};
console.log("presentationData", presentationData);
// Regular view
return (
<div className="flex overflow-hidden flex-col">

View file

@ -52,13 +52,11 @@ const SlideContent = ({
try {
const response = await PresentationGenerationApi.editSlide(
presentationId,
slide.index,
slide.id,
value
);
if (response) {
console.log("response", response);
dispatch(updateSlide({ index: slide.index, slide: response }));
toast.success("Slide updated successfully");
}

View file

@ -65,20 +65,18 @@ export class PresentationGenerationApi {
static async editSlide(
presentation_id: string,
index: number,
slide_id: string,
prompt: string
) {
try {
const response = await fetch(
`/api/v1/ppt/edit`,
`/api/v1/ppt/slide/edit`,
{
method: "POST",
headers: getHeader(),
body: JSON.stringify({
presentation_id,
index,
id: slide_id,
prompt,
}),
cache: "no-cache",

View file

@ -13,7 +13,7 @@ export async function POST(req: NextRequest) {
return NextResponse.json({ error: "Missing Presentation ID" }, { status: 400 });
}
const browser = await puppeteer.launch({
headless: true,
headless: false,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
@ -31,6 +31,7 @@ export async function POST(req: NextRequest) {
width: "1280px",
height: "720px",
margin: { top: 0, right: 0, bottom: 0, left: 0 }
});
browser.close();
const sanitizedTitle = sanitizeFilename(title);