From 8e87d834bc30917a63a122a2f269f4ce9bb33a21 Mon Sep 17 00:00:00 2001 From: cdricms <36056008+cdricms@users.noreply.github.com> Date: Mon, 10 Feb 2025 08:52:32 +0100 Subject: [PATCH] Shortcodes --- backend/api/media/media.go | 3 +- backend/api/media/update.go | 51 ++++- backend/api/media_routes.go | 8 +- backend/api/shortcodes/shortcode.go | 13 ++ .../20250205081449_add_events_title.down.sql | 1 + .../20250205081449_add_events_title.up.sql | 1 + backend/core/models/events.go | 2 +- .../app/(auth)/dashboard/blogs/new/page.tsx | 141 +++++++++++++ .../(auth)/dashboard/members/[uuid]/page.tsx | 2 +- .../(auth)/dashboard/settings/media/old.tsx | 30 --- .../(auth)/dashboard/settings/media/page.tsx | 17 +- frontend/app/(main)/page.tsx | 27 ++- frontend/components/hero.tsx | 15 +- frontend/components/photo-dialog.tsx | 4 +- frontend/components/shortcode-dialogue.tsx | 192 ++++++++++++++++-- frontend/lib/getShortcode.ts | 13 ++ frontend/lib/request.ts | 1 - frontend/package-lock.json | 30 +++ frontend/package.json | 2 + frontend/tailwind.config.ts | 3 + 20 files changed, 485 insertions(+), 71 deletions(-) create mode 100644 backend/cmd/migrate/migrations/20250205081449_add_events_title.down.sql create mode 100644 backend/cmd/migrate/migrations/20250205081449_add_events_title.up.sql create mode 100644 frontend/app/(auth)/dashboard/blogs/new/page.tsx delete mode 100644 frontend/app/(auth)/dashboard/settings/media/old.tsx create mode 100644 frontend/lib/getShortcode.ts diff --git a/backend/api/media/media.go b/backend/api/media/media.go index ab9a842..5d8dc1f 100644 --- a/backend/api/media/media.go +++ b/backend/api/media/media.go @@ -36,7 +36,8 @@ func HandleMedia(w http.ResponseWriter, r *http.Request) { Model((*models.Media)(nil)). Count(context.Background()) - totalPages := int(math.Max(1, float64(total/limit))) + upperBound := float64(total) / float64(limit) + totalPages := int(math.Max(1, math.Ceil(upperBound))) var media []models.Media err = core.DB.NewSelect(). diff --git a/backend/api/media/update.go b/backend/api/media/update.go index 83e39a0..7a52895 100644 --- a/backend/api/media/update.go +++ b/backend/api/media/update.go @@ -1,3 +1,52 @@ package media -// TODO +import ( + "context" + "encoding/json" + "net/http" + + "fr.latosa-escrima/core" + "fr.latosa-escrima/core/models" + "github.com/google/uuid" +) + +func HandleUpdate(w http.ResponseWriter, r *http.Request) { + var media models.Media + err := json.NewDecoder(r.Body).Decode(&media) + if err != nil { + core.JSONError{ + Status: core.Error, + Message: err.Error(), + }.Respond(w, http.StatusBadRequest) + return + } + media_uuid := r.PathValue("media_uuid") + media.ID, err = uuid.Parse(media_uuid) + if err != nil { + core.JSONError{ + Status: core.Error, + Message: err.Error(), + }.Respond(w, http.StatusBadRequest) + return + } + + _, err = core.DB.NewUpdate(). + Model(&media). + OmitZero(). + WherePK(). + Exec(context.Background()) + if err != nil { + core.JSONError{ + Status: core.Error, + Message: err.Error(), + }.Respond(w, http.StatusInternalServerError) + return + } + + core.JSONSuccess{ + Status: core.Success, + Message: "Media updated", + Data: media, + }.Respond(w, http.StatusOK) + +} diff --git a/backend/api/media_routes.go b/backend/api/media_routes.go index 87db6f6..7a6cbf0 100644 --- a/backend/api/media_routes.go +++ b/backend/api/media_routes.go @@ -28,10 +28,10 @@ var MediaRoutes = map[string]core.Handler{ Handler: media.HandleMediaFile, Middlewares: []core.Middleware{Methods("GET")}, }, - // "/media/{media_uuid}/update": { - // Handler: HandleGetMediaFile, - // Middlewares: []core.Middleware{Methods("PATCH"), AuthJWT}, - // }, + "/media/{media_uuid}/update": { + Handler: media.HandleUpdate, + Middlewares: []core.Middleware{Methods("PATCH"), AuthJWT}, + }, "/media/{media_uuid}/delete": { Handler: media.HandleDelete, Middlewares: []core.Middleware{Methods("DELETE"), AuthJWT}, diff --git a/backend/api/shortcodes/shortcode.go b/backend/api/shortcodes/shortcode.go index 893a020..5eb94c9 100644 --- a/backend/api/shortcodes/shortcode.go +++ b/backend/api/shortcodes/shortcode.go @@ -2,6 +2,7 @@ package shortcodes import ( "context" + "fmt" "net/http" "fr.latosa-escrima/core" @@ -14,6 +15,7 @@ func HandleShortcode(w http.ResponseWriter, r *http.Request) { err := core.DB.NewSelect(). Model(&shortcode). Where("code = ?", code). + Relation("Media"). Limit(1). Scan(context.Background()) if err != nil { @@ -24,6 +26,17 @@ func HandleShortcode(w http.ResponseWriter, r *http.Request) { return } + scheme := "http" + if r.TLS != nil { // Check if the request is over HTTPS + scheme = "https" + } + + // Extract the host + host := r.Host + baseURL := fmt.Sprintf("%s://%s", scheme, host) + if shortcode.Media != nil { + shortcode.Media.URL = fmt.Sprintf("%s/media/%s/file", baseURL, shortcode.Media.ID) + } core.JSONSuccess{ Status: core.Success, Message: "Shortcode found", diff --git a/backend/cmd/migrate/migrations/20250205081449_add_events_title.down.sql b/backend/cmd/migrate/migrations/20250205081449_add_events_title.down.sql new file mode 100644 index 0000000..08f950c --- /dev/null +++ b/backend/cmd/migrate/migrations/20250205081449_add_events_title.down.sql @@ -0,0 +1 @@ +ALTER TABLE events DROP COLUMN title; diff --git a/backend/cmd/migrate/migrations/20250205081449_add_events_title.up.sql b/backend/cmd/migrate/migrations/20250205081449_add_events_title.up.sql new file mode 100644 index 0000000..d1da967 --- /dev/null +++ b/backend/cmd/migrate/migrations/20250205081449_add_events_title.up.sql @@ -0,0 +1 @@ +ALTER TABLE events ADD COLUMN title text not null default ''; diff --git a/backend/core/models/events.go b/backend/core/models/events.go index f350f13..7c5a5c7 100644 --- a/backend/core/models/events.go +++ b/backend/core/models/events.go @@ -18,7 +18,7 @@ type Event struct { bun.BaseModel `bun:"table:events"` EventID uuid.UUID `bun:"event_id,type:uuid,pk,default:gen_random_uuid()" json:"id"` - Title string `bun:"title,notnull" json:"title"` + Title string `bun:"title,notnull" json:"title"` CreationDate time.Time `bun:"creation_date,notnull,default:current_timestamp" json:"creationDate"` ScheduleStart time.Time `bun:"schedule_start,notnull" json:"start"` ScheduleEnd time.Time `bun:"schedule_end,notnull" json:"end"` diff --git a/frontend/app/(auth)/dashboard/blogs/new/page.tsx b/frontend/app/(auth)/dashboard/blogs/new/page.tsx new file mode 100644 index 0000000..1c51103 --- /dev/null +++ b/frontend/app/(auth)/dashboard/blogs/new/page.tsx @@ -0,0 +1,141 @@ +"use client"; + +import { Textarea } from "@/components/ui/textarea"; +import { useEffect, useRef, useState } from "react"; +import { marked } from "marked"; +import DOMPurify from "dompurify"; +import { Button } from "@/components/ui/button"; +import { Bold, Italic, Link, Strikethrough, Underline } from "lucide-react"; + +enum Command { + Italic = "*", + Bold = "**", + Strikethrough = "~~", + Underline = "__", +} + +export default function NewBlog() { + const ref = useRef(null); + const [text, setText] = useState(""); + const [cursor, setCursor] = useState<{ line: number; column: number }>({ + line: 0, + column: 0, + }); + const [selection, setSelection] = useState<{ + start: number; + end: number; + } | null>(null); + + const getCursorPosition = ( + event: React.ChangeEvent, + ) => { + const textarea = event.target; + const text = textarea.value; + const cursorPos = textarea.selectionStart; + + const lines = text.substring(0, cursorPos).split("\n"); + const line = lines.length; // Current line number (1-based) + const column = lines[lines.length - 1].length + 1; // Current column (1-based) + + setCursor({ line, column }); + }; + + const onSelect = (event: React.ChangeEvent) => { + const { selectionStart, selectionEnd } = event.currentTarget; + if (selectionStart === selectionEnd) return; + + setSelection({ start: selectionStart, end: selectionEnd }); + }; + + useEffect(() => { + setSelection(null); + }, [text]); + + const moveCursor = (newPos: number) => { + if (!ref.current) return; + ref.current.selectionEnd = newPos; + ref.current.focus(); + }; + + const execCommand = (command: Command, symetry: boolean = true) => { + if (selection) { + const selectedText = text.substring(selection.start, selection.end); + const pre = text.slice(0, selection.start); + const post = text.slice(selection.end); + const newSelectedText = `${command}${selectedText}${symetry ? command : ""}`; + setText(pre + newSelectedText + post); + return; + } + + const pre = text.slice(0, cursor.column); + const post = text.slice(cursor.column); + + if (!symetry) setText(pre + command + post); + else { + const t = pre + command + command + post; + setText(t); + } + console.log(pre.length + command.length); + moveCursor(cursor.column + 2); + }; + + return ( +
+
+
+ + + + + {/* */} +
+