TipTap Output and Rendering

59 views Asked by At

My problem is the follwoing:

Setup: Java Spring Boot api connected with MongoDB to handle my Sever responses and Requestes.

Entity:

package org.schmeckis.backend.model;

import lombok.With;
import org.schmeckis.backend.model.submodel.Kategorie;
import org.springframework.data.annotation.Id;

import java.util.List;

public record Rezept(

        @Id
        String id,

        String rezeptName,
        @With
        String rezeptImageUrl,

        String rezeptKurzbeschreibung, // to be JSON and Edited by TIPTAP

        String rezeptBeschreibung, // to be JSON and Edited by TIPTAP

        List<Kategorie> kategorieList
) {

        public Rezept {
                if (rezeptImageUrl == null) {
                        rezeptImageUrl = "";
                }
        }

}

RestController:

package org.schmeckis.backend.controller;

import lombok.RequiredArgsConstructor;
import org.schmeckis.backend.model.Rezept;
import org.schmeckis.backend.model.dto.RequestRezept;
import org.schmeckis.backend.model.submodel.Kategorie;
import org.schmeckis.backend.service.RezeptService;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/rezepte")
@RequiredArgsConstructor
public class RezepteController {

    private final RezeptService rezeptService;

    @GetMapping
    public List<Rezept> getAllRezepte() {
        return rezeptService.getAllRezepte();
    }

    @PostMapping("/create")
    @ResponseStatus(HttpStatus.CREATED)
    public Rezept createRezept(@RequestBody RequestRezept rezept) {
        return rezeptService.createRezept(rezept);
    }

    @GetMapping("/{id}")
    public Rezept getRezept(@PathVariable String id) {
        return rezeptService.getRezept(id);
    }

    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteRezept(@PathVariable String id) {
        rezeptService.deleteRezept(id);
    }

    @PutMapping("/{id}")
    @ResponseStatus(HttpStatus.OK)
    public Rezept updateRezept(@PathVariable String id, @RequestBody RequestRezept rezept) {
        return rezeptService.updateRezept(id, rezept);
    }

    @PutMapping("/{id}/addKategorie")
    @ResponseStatus(HttpStatus.OK)
    public Rezept addKategorieToRezept(@PathVariable String id, @RequestBody Kategorie kategorie) {
        return rezeptService.addKategorieToRezept(id, kategorie);
    }

    @DeleteMapping("/{id}/deleteKategorie")
    @ResponseStatus(HttpStatus.OK)
    public Rezept deleteKategorieFromRezept(@PathVariable String id, @RequestBody Kategorie kategorie) {
        return rezeptService.deleteKategorieFromRezept(id, kategorie);
    }

    @GetMapping("/kategorie/{kategorieName}")
    public List<Rezept> getRezepteByKategorie(@PathVariable String kategorieName) {
        return rezeptService.getRezepteByKategorie(kategorieName);
    }


}

React/Vite frontend Setup:

In this Setup I want to be able to create via the TipTap Rich Text Editor a nice looking text for displaying. This text has to be stored with in my Entity in my Backend and should be rendered when outputted again in the Frontend.

I already refrained from the Idea to get the HTML from the editor to my Backend because of* XSS*, but with a JSON I´m quite lost on how to render it when it is requested in the frontend.

My Idea was to save JSON as a string in the Backend. But I haven´t really found out how I can use the Data given to the forntend by the Backend to render it in the form i orginally intended it for. Could somebody point me in the right direction because the documentation doesn´t really help me.

EDITOR:

import {EditorContent, useEditor} from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
import {Toolbar} from "./ToolBar.tsx";


export default function RichTextEditor({
                                           rezeptBeschreibung,
                                           onChange,
                                       }: {
    rezeptBeschreibung: string;
    onChange: (rezeptBeschreibung: string) => void;

}) {
    const editor = useEditor({
        extensions: [StarterKit.configure()],
        content: rezeptBeschreibung,
        editorProps: {
            attributes: {
                class: "rounded border-none p-4 m-4 min-h-[300px] shadow-doubleOut active:shadow-doubleIn",
            }

        },
        onUpdate({editor}) {
            onChange(editor.getJSON().toString());
        },
    });
    return (
        <div className="flex flex-col justify-stretch min-h-[250px] min-w-[300px] overflow-y-scroll">
            <Toolbar editor={editor}/>
            <EditorContent editor={editor}/>
        </div>
    );
}

Output:

import * as React from 'react';
import {Rezept} from '../models/Rezept.tsx';
import {useNavigate} from "react-router-dom";
import {MdInfoOutline} from 'react-icons/md';


type RezeptProps = {
    rezept: Rezept
}

export default function RezeptCard({rezept}: RezeptProps) {
    const navigate = useNavigate();

    function openDetails() {
        navigate("/rezept/" + rezept.id);
    }
    return (
        <div className="bg-offWhite rounded-xl shadow-doubleOut p-10 m-2 border-none hover:shadow-doubleIn">
            <div className="flex justify-between items-center">
                <h2 className="text-2xl font-bold text-center justify-center text-textHeader ml-4">{rezept.rezeptName}</h2>
                <button className="bg-offWhite hover:shadow-buttonIn rounded-full p-2 w-auto" onClick={openDetails}>
                    <MdInfoOutline size="30" color="#646464"/>
                </button>
            </div>
            <img className="w-50 border-transparent shadow-doubleIn object-cover mt-2 mb-2 rounded"
                 src={rezept.rezeptImageUrl} alt={rezept.rezeptName}/>
            <p className="text-textPrime mt-8">{rezept.rezeptKurzbeschreibung}</p> // here Json    // should be Re-rendered I know i have to create a Component. But im quite lost on how 
            <div className="flex mt-4">
                {rezept.kategorieList.map(kategorie => (
                    <button key={kategorie.kategorieName}
                            className="flex-row shadow-hashtagbutton hover:shadow-hashtagbuttonOut bg-offWhite rounded-full px-6 py-1.5 text-m font-semibold text-textPrime mr-2 mb-2 ">#{kategorie.kategorieName}</button>
                ))}
            </div>
        </div>

    );
}

I´m very new to the whole thing so im quite lost I would also be very happy when you could just point me in the right direction.

Can you help me find a way to convert the **JSON **stored as a string into a HTML code displayed on the frontend ? and to keep all stylings made within the JSON

0

There are 0 answers