Gibt es eine bessere Möglichkeit, diese hartnäckigen Daten in der Benutzeroberfläche anzuzeigen?

Post a reply

Smilies
:) :( :oops: :chelo: :roll: :wink: :muza: :sorry: :angel: :read: *x) :clever:
View more smilies

BBCode is ON
[img] is ON
[flash] is OFF
[url] is ON
Smilies are ON

Topic review
   

Expand view Topic review: Gibt es eine bessere Möglichkeit, diese hartnäckigen Daten in der Benutzeroberfläche anzuzeigen?

by Guest » 20 Jan 2025, 17:43

Ich versuche, einige Daten, die ich aus der Datenbank abgerufen habe, in der Benutzeroberfläche anzuzeigen. Allerdings wird nur ein Teil der zurückgegebenen Daten angezeigt, obwohl Routenhandler so eingerichtet sind, dass sie alle gespeicherten Daten zurückgeben.
Das unten ist eine Kopie meines route.js-Codes:

Code: Select all

import { NextResponse } from 'next/server';
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export async function POST(req) {
let script = null;
let user = null;

try {
const body = await req.json();
script = body.script;
user = body.user;

// Validate input
if (!script || !user) {
throw new Error("Invalid request payload: 'script' and 'user' are required.");
}

if (!script.id) {
throw new Error("Script ID is required.");
}

if (!Array.isArray(script.scenes)) {
throw new Error("Scenes must be an array.");
}

const appwriteId = user?.$id;
if (!appwriteId) {
throw new Error("User ID is required.");
}

// Ensure the user exists in the database
const foundUser = await prisma.user.upsert({
where: { appwriteId },
update: {},
create: {
appwriteId,
email: user.email,
name: user.name,
},
});

// Upsert the script
const savedScript = await prisma.script.upsert({
where: { id: script.id },
update: {
title: script.title || '',
type: script.type || 'feature',
genre: script.genre || '',
},
create: {
title: script.title || '',
type: script.type || 'feature',
genre: script.genre || '',
userId: foundUser.id,
},
});

if (!savedScript || !savedScript.id) {
throw new Error('Failed to upsert script.');
}

// Delete related entities before deleting scenes
const existingSceneIds = (
await prisma.scene.findMany({
where: { scriptId: savedScript.id },
select: { id: true },
})
).map((scene) => scene.id);

if (existingSceneIds.length > 0) {
// Delete lines related to sceneCharacters
await prisma.line.deleteMany({
where: { sceneCharacter: { sceneId: { in: existingSceneIds } } },
});

// Delete sceneCharacters related to scenes
await prisma.sceneCharacter.deleteMany({
where: { sceneId: { in: existingSceneIds } },
});

// Delete the scenes themselves
await prisma.scene.deleteMany({
where: { id: { in: existingSceneIds } },
});
}

// Recreate scenes
const scenesWithScriptId = script.scenes.map((scene, index) => ({
title: scene.title || '',
location: scene.location || '',
description: scene.description || '',
shot: scene.shot || '',
order: index,
scriptId: savedScript.id,
}));

if (scenesWithScriptId.length > 0) {
await prisma.scene.createMany({
data: scenesWithScriptId,
});
}

// Fetch the saved script with ordered scenes
const fetchedScript = await prisma.script.findUnique({
where: { id: savedScript.id },
include: {
scenes: {
orderBy: { order: 'asc' },
},
},
});

return NextResponse.json(fetchedScript);
} catch (error) {
console.error('Error while saving script:', {
message: error.message,
stack: error.stack,
script,
user,
});

return NextResponse.json(
{ error: "An error occurred while saving the script."  },
{ status: 500 }
);
}
}

export async function GET() {
try {
const scripts = await prisma.script.findMany({
include: {
scenes: {
include: {
sceneCharacters: {
include: {
character: true,
lines: true,
},
},
},
},
},
});

console.log("SCRIPT FROM DB", scripts);

return NextResponse.json(scripts);
} catch (error) {
console.error('Error while fetching scripts:', error.message);
return NextResponse.json(
{ error: "An error occurred while fetching the scripts." },
{ status: 500 }
);
}
}

und das Folgende ist der UI-Code, der die Daten abruft und anzeigt:

Code: Select all

import React, { useState, useEffect } from "react";
import {
Modal,
ModalContent,
ModalHeader,
ModalBody,
ModalFooter,
} from "@nextui-org/react";

const EditScript = ({
isOpen,
onClose,
editScripts = [],
selectedScriptId,
user,
}) => {
const [editableScript, setEditableScript] = useState(null);
const [isEditing, setIsEditing] = useState(false);

useEffect(() => {
if (!isOpen) return;
const currentScript = editScripts.find(
(script) => script.id === selectedScriptId
);
if (currentScript) {
console.log("Fetched script:", JSON.stringify(currentScript, null, 2));
setEditableScript(currentScript);
} else {
console.error(`Script with ID ${selectedScriptId} not found.`);
}
}, [isOpen, editScripts, selectedScriptId]);

//Saving the data 👇🏾
const saveEdit = async () => {
if (!editableScript || !editableScript.id) {
console.error("No script or ID to save.");
return;
}
try {
const response = await fetch("/api/scripts/editScriptV2", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
script: {
...editableScript,
scenes: editableScript.scenes.map((scene) => ({
id: scene.id || null,
title: scene.title || "",
location: scene.location || "",
description: scene.description || "",
shot: scene.shot || "",
order: scene.order,
})),
},
scriptType: editableScript?.type,
user,
}),
});
if (!response.ok) {
throw new Error(`Failed to save script: ${response.statusText}`);
}
console.log("Script saved successfully:", editableScript);
onClose();
} catch (error) {
console.error("Error saving script:", error);
}
};

const handleSceneChange = (index, field, value) => {
setEditableScript((prev) => ({
...prev,
scenes: prev.scenes.map((scene, i) =>
i === index ? { ...scene, [field]: value } : scene
),
}));
};

const handleDownload = () => {
if (!editableScript) return;

const blob = new Blob([JSON.stringify(editableScript, null, 2)], {
type: "application/json",
});
const url = URL.createObjectURL(blob);

const link = document.createElement("a");
link.href = url;
link.download = `${editableScript.title || "script"}.json`;
link.click();

URL.revokeObjectURL(url);
};

const renderScenes = () => {
if (!editableScript || !editableScript.scenes) {
return 
No scenes available.
;
}

return editableScript.scenes.map((scene, index) =>  (


{isEditing ? (

handleSceneChange(index, "title", e.target.value)
}
className="border p-1 w-full"
/>
) : (
scene.title || `Scene ${index + 1}`
)}


[b]Location:[/b]{" "}
{isEditing ? (

handleSceneChange(index, "location", e.target.value)
}
className="border p-1 w-full"
/>
) : (
scene.location || "N/A"
)}

[b]Description:[/b]{" "}
{isEditing ? (

handleSceneChange(index, "description", e.target.value)
}
className="border p-1 w-full"
/>
) : (
scene.description || "N/A"
)}

[b]Shot:[/b]{" "}
{isEditing ? (
 handleSceneChange(index, "shot", e.target.value)}
className="border p-1 w-full"
/>
) : (
scene.shot || "N/A"
)}

[b]Order:[/b]{" "}
{isEditing ? (

handleSceneChange(index, "order", e.target.value)
}
className="border p-1 w-full"
/>
) : (
scene.order || "N/A"
)}


[h4]Characters & Dialogue:[/h4]
{scene.sceneCharacters && scene.sceneCharacters.length > 0 ? (
scene.sceneCharacters.map((character, charIndex) => (


{isEditing ? (

handleSceneChange(index, "sceneCharacters", [
...scene.sceneCharacters.slice(0, charIndex),
{
...character,
character: {
...character.character,
name: e.target.value,
},
},
...scene.sceneCharacters.slice(charIndex + 1),
])
}
className="border p-1"
/>
) : (
character.character.name?.toUpperCase() ||
"Unnamed Character"
)}

{scene.Dialogue &&
scene.Dialogue.filter(
(dialogue) =>
dialogue.character === character.character.name
).map((dialogue, dialogueIndex) => (

{dialogue.lines.map((line, lineIndex) =>  (

{isEditing ? (

handleSceneChange(index, "Dialogue", [
...scene.Dialogue.slice(0, dialogueIndex),
{
...dialogue,
lines: dialogue.lines.map((l, li) =>
li === lineIndex
? { ...l, content: e.target.value }
: l
),
},
...scene.Dialogue.slice(dialogueIndex + 1),
])
}
className="border p-1 w-full"
/>
) : (
line.content
)}

))}

))}

))
) : (
No characters or dialogue available.
)}


));
};

const renderSegments = () => {
return (



Video
Audio



{editableScript.scenes?.length > 0 ? (
editableScript.scenes.map((scene, index) => (


{isEditing ? (

handleSceneChange(index, "title", e.target.value)
}
className="border p-1 w-full"
/>
) : (
scene.title
)}


{isEditing ? (

handleSceneChange(index, "description", e.target.value)
}
className="border p-1 w-full"
/>
) : (
scene.description
)}


))
) : (


No scenes available.


)}


);
};

if (!editableScript) {
return (


No Script Selected

Please select a script to edit.


Close



);
}

return (



{editableScript.title || "Edit Script"}


{editableScript.type === "feature" ||
editableScript.type === "series" ? (
renderScenes()
) : editableScript.type === "short" ||
editableScript.type === "commercial" ? (
renderSegments()
) : (
Script type not supported.
)}



Close


Download Script

{isEditing ? (

 saveEdit()}
>
Save Changes

 setIsEditing(false)}
>
Cancel Changes


) : (
  setIsEditing(true)}
disabled={
!["feature", "series", "short", "commercial"].includes(
editableScript?.type
)
}
>
Edit

)}



);
};

export default EditScript;
Zuletzt finden Sie unten eine Kopie meines schema.prisma:

Code: Select all

generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "postgresql"
url      = env("DATABASE_URL")
}

enum MembershipStatus {
Free
Paid
}

enum NumberType {
Voice
SMS
Both
}

enum ContentType {
MOVIE
TRAILER
SHORT
SERIES
}

enum Role {
USER
ADMIN
}

model User {
id               String           @id @default(uuid())
name             String?
email            String           @unique
appwriteId       String           @unique
membershipStatus MembershipStatus @default(Free)
stripeCustomerId String?          @unique
provider         String           @default("")
providerId       String?
role             Role             @default(USER)
createdAt        DateTime         @default(now())
updatedAt        DateTime         @default(now()) @updatedAt

Post        Post[]
Profile     Profile?
Movie       Movie[]
Stream      Stream[]
Trailer     Trailer[]
Scene       Scene[]
Character   Character[]
Content     Content[]
phoneNumber Number[]
scripts     Script[]
}

model Genre {
id   Int    @id @default(autoincrement())
name String @unique
}

model Content {
id          Int         @id @default(autoincrement())
title       String
url         String
genres      String
subGenre    String?
contentType ContentType
movieId     String?
trailerId   Int?
scenes      Scene[]
user_id     String
user        User        @relation(fields: [user_id], references: [id])
Trailer     Trailer?

@@unique([title, url, user_id])
}

model Script {
id        Int      @id @default(autoincrement())
title     String
genre     String?
type      String?
userId    String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
scenes    Scene[]
user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)

// @@unique([userId, title])
}

model AdShortScript {
id           String    @id @default(uuid()) // Primary key is a UUID
title        String    @unique
hook         String
segments     Segment[]
callToAction String
createdAt    DateTime  @default(now())
updatedAt    DateTime  @updatedAt
}

model Segment {
id       String        @id @default(uuid()) // Primary key is a UUID
video    String
audio    String
order    Int?
scriptId String
script   AdShortScript @relation(fields: [scriptId], references: [id])
}

model Scene {
id              Int              @id @default(autoincrement())
title           String
location        String?
description     String?
shot            String // Required
order           Int // Required
createdAt       DateTime         @default(now())
updatedAt       DateTime         @updatedAt
scriptId        Int
script          Script           @relation(fields: [scriptId], references: [id], onDelete: Cascade)
sceneCharacters SceneCharacter[] @relation("SceneToCharacters")
userId          String?
user            User?            @relation(fields: [userId], references: [id])
Trailer         Trailer?         @relation(fields: [trailerId], references: [id])
trailerId       Int?
Content         Content?         @relation(fields: [contentId], references: [id])
contentId       Int?
Character       Character[]
Dialogue        Dialogue[]

@@map("scenes")
}

model SceneCharacter {
id          Int       @id @default(autoincrement())
scene       Scene     @relation("SceneToCharacters", fields: [sceneId], references: [id], onDelete: Cascade)
sceneId     Int
character   Character @relation(fields: [characterId], references:  [id])
characterId Int
lines       Line[]

// @@map("scene_characters")
}

model Line {
id               Int            @id @default(autoincrement())
content          String
sentiment        String?
sceneCharacter   SceneCharacter @relation(fields: [sceneCharacterId], references: [id])
sceneCharacterId Int
Character        Character?     @relation(fields: [characterId], references: [id])
characterId      Int?
Dialogue         Dialogue?      @relation(fields: [dialogueId], references: [id])
dialogueId       Int?

// @@map("lines")
}

model Character {
id                Int     @id @default(autoincrement())
name              String?
description       String?
attributes        String?
url               String?
characterRefImage String?
emotionalImpact   String?

scenes  SceneCharacter[]
lines   Line[]
user    User?            @relation(fields: [userId], references: [id])
userId  String?
Scene   Scene?           @relation(fields: [sceneId], references: [id])
sceneId Int?

@@unique([name, userId])
}

model Dialogue {
id        Int      @id @default(autoincrement())
sceneId   Int
scene     Scene    @relation(fields: [sceneId], references: [id])
character String
lines     Line[]
order     Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

model Category {
id      Int      @id @default(autoincrement())
name    String
streams Stream[]
}

model Stamp {
id        Int      @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
Das erwartete Verhalten besteht darin, die Daten anzuzeigen, genauer gesagt die Szenen einschließlich der Zeichen und Zeilen. Bitte helfen Sie herauszufinden, warum die Zeichen und Zeilen nicht wie erwartet angezeigt werden. Hier ist eine Kopie der Antwort, als der Code ausgeführt wurde:

Code: Select all

[
{
"id": 130,
"title": "ENCHANTED REALM\n\n By\n\n Screenplay Author",
"genre": "Screenplay Author",
"type": "feature",
"userId": "5fa953db-9875-4b14-bd23-8d24c6cc6a99",
"createdAt": "2025-01-20T03:08:49.097Z",
"updatedAt": "2025-01-20T16:11:38.767Z",
"scenes": [
{
"id": 659,
"title": "INT. MYSTIC SHOP - DAY",
"location": "INT. MYSTIC SHOP - DAY",
"description": "The room is filled with strange and exotic items, shelves upon shelves of magical artifacts and dusty tomes. We see ESON, a young woman in her early twenties, with a curious expression, browsing through the shelves. She is being helped by the shop owner, ZEPSOR, an eccentric old man with a wild look in his eye.",
"shot": "The room is filled with strange and exotic items, shelves upon shelves of magical artifacts and dusty tomes. We see EMILY WILSON, a young woman in her early twenties, with a curious expression, browsing through the shelves. She is being helped by the shop owner, ZEPHYR WINDSOR, an eccentric old man with a wild look in his eye. ",
"order": 0,
"createdAt": "2025-01-20T16:11:39.287Z",
"updatedAt": "2025-01-20T16:11:39.287Z",
"scriptId": 130,
"userId": null,
"trailerId": null,
"contentId": null,
"sceneCharacters": []
},
{
"id": 660,
"title": "EXT. MYSOP - DAY",
"location": "EXT. MYSTIC SHOP - DAY",
"description": "The camera pans out, showing the small town of Willowdale. The streets are lined with old buildings, and the air is filled with the smell of magic. We see EMILY and ZEPHYR standing outside the shop, looking up at the sky.",
"shot": "The camera pans out, showing the small town of Willowdale. The streets are lined with old buildings, and the air is filled with the smell of magic. We see EMILY and ZEPHYR standing outside the shop, looking up at the sky.  ",
"order": 1,
"createdAt": "2025-01-20T16:11:39.287Z",
"updatedAt": "2025-01-20T16:11:39.287Z",
"scriptId": 130,
"userId": null,
"trailerId": null,
"contentId": null,
"sceneCharacters": []
},
{
"id": 661,
"title": "INT. TOWN HALL - NIGHT",
"location": "INT. TOWN HALL - NIGHT",
"description": "The room is filled with townspeople, all gathered to discuss the strange occurrences that have been happening in Willowdale. We see EY and ZEYR standing at the front of the room, facing the crowd. ",
"shot": "The room is filled with townspeople, all gathered to discuss the strange occurrences that have been happening in Willowdale. We see EMILY and ZEPHYR standing at the front of the room, facing the crowd. ",
"order": 2,
"createdAt": "2025-01-20T16:11:39.287Z",
"updatedAt": "2025-01-20T16:11:39.287Z",
"scriptId": 130,
"userId": null,
"trailerId": null,
"contentId": null,
"sceneCharacters": []
}
]
}
]

Top