From a13f80cf07a838d7648819adb408cc95625d0427 Mon Sep 17 00:00:00 2001 From: qdust41 Date: Mon, 30 Mar 2026 02:06:15 -0400 Subject: [PATCH] Working basic frontend implementation --- assets/js/index.tsx | 260 +++++++++++++----- lib/mixer/accounts/user.ex | 2 + lib/mixer/posts/tweet.ex | 16 +- lib/mixer_web/controllers/page_controller.ex | 6 +- .../controllers/page_html/index.html.heex | 5 +- lib/mixer_web/router.ex | 1 + 6 files changed, 220 insertions(+), 70 deletions(-) diff --git a/assets/js/index.tsx b/assets/js/index.tsx index ea2e75a..6fff9b9 100644 --- a/assets/js/index.tsx +++ b/assets/js/index.tsx @@ -1,86 +1,214 @@ -import React, { useEffect } from "react"; +import React, { useEffect, useState } from "react"; import { createRoot } from "react-dom/client"; -import { initLandingPage } from "./animation"; +import { + readTweet, + createTweet, + destroyTweet, + buildCSRFHeaders, +} from "./ash_rpc"; + +type Tweet = { + id: string; + content: string; + userId: string; + state: "posted" | "drafted"; +}; + +function TweetCompose({ onPosted }: { onPosted: (tweet: Tweet) => void }) { + const [content, setContent] = useState(""); + const [submitting, setSubmitting] = useState(false); + const [error, setError] = useState(null); + + async function handleSubmit(e: React.FormEvent) { + e.preventDefault(); + if (!content.trim()) return; + setSubmitting(true); + setError(null); + const result = await createTweet({ + input: { content: content.trim() }, + fields: ["id", "content", "userId", "state"], + headers: buildCSRFHeaders(), + }); + setSubmitting(false); + if (result.success) { + onPosted(result.data as Tweet); + setContent(""); + } else { + setError(result.errors.map((e) => e.message).join(", ")); + } + } + + return ( +
+