fix(settings): preserve stored logo + persist editor changes on save
This commit is contained in:
@@ -58,6 +58,12 @@ export function RichTextEditor({
|
|||||||
const [mounted, setMounted] = useState(false);
|
const [mounted, setMounted] = useState(false);
|
||||||
useEffect(() => setMounted(true), []);
|
useEffect(() => setMounted(true), []);
|
||||||
|
|
||||||
|
// Mirror editor HTML into local state so the hidden <input> always
|
||||||
|
// reflects the latest content. Without this, React doesn't re-render
|
||||||
|
// when TipTap's content changes and the form submits stale HTML.
|
||||||
|
const initialHtml = swapCidToLogo(defaultValue || "<p></p>", logoDataUrl);
|
||||||
|
const [html, setHtml] = useState(initialHtml);
|
||||||
|
|
||||||
const editor = useEditor({
|
const editor = useEditor({
|
||||||
immediatelyRender: false,
|
immediatelyRender: false,
|
||||||
extensions: [
|
extensions: [
|
||||||
@@ -85,6 +91,9 @@ export function RichTextEditor({
|
|||||||
Color,
|
Color,
|
||||||
],
|
],
|
||||||
content: swapCidToLogo(defaultValue || "<p></p>", logoDataUrl),
|
content: swapCidToLogo(defaultValue || "<p></p>", logoDataUrl),
|
||||||
|
onUpdate: ({ editor }) => {
|
||||||
|
setHtml(editor.getHTML());
|
||||||
|
},
|
||||||
editorProps: {
|
editorProps: {
|
||||||
attributes: {
|
attributes: {
|
||||||
class: "wysiwyg-editor",
|
class: "wysiwyg-editor",
|
||||||
@@ -96,7 +105,7 @@ export function RichTextEditor({
|
|||||||
// Keep editor disposed cleanly on unmount.
|
// Keep editor disposed cleanly on unmount.
|
||||||
useEffect(() => () => editor?.destroy(), [editor]);
|
useEffect(() => () => editor?.destroy(), [editor]);
|
||||||
|
|
||||||
const html = swapLogoToCid(editor?.getHTML() ?? defaultValue, logoDataUrl);
|
const submittedHtml = swapLogoToCid(html, logoDataUrl);
|
||||||
|
|
||||||
if (!mounted) {
|
if (!mounted) {
|
||||||
// Server / pre-hydration fallback: a textarea so the value is still
|
// Server / pre-hydration fallback: a textarea so the value is still
|
||||||
@@ -219,7 +228,7 @@ export function RichTextEditor({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<EditorContent editor={editor} />
|
<EditorContent editor={editor} />
|
||||||
<input type="hidden" name={name} value={html} />
|
<input type="hidden" name={name} value={submittedHtml} />
|
||||||
{variables.length > 0 ? (
|
{variables.length > 0 ? (
|
||||||
<div style={{ marginTop: 6, display: "flex", flexWrap: "wrap", gap: 4, alignItems: "center" }}>
|
<div style={{ marginTop: 6, display: "flex", flexWrap: "wrap", gap: 4, alignItems: "center" }}>
|
||||||
<span style={{ fontSize: 12, color: "#6d7175", marginRight: 4 }}>Insert variable:</span>
|
<span style={{ fontSize: 12, color: "#6d7175", marginRight: 4 }}>Insert variable:</span>
|
||||||
|
|||||||
@@ -101,12 +101,21 @@ export const action = async ({ request }: ActionFunctionArgs) => {
|
|||||||
// 2. Remove the current logo (`removeLogo=on`).
|
// 2. Remove the current logo (`removeLogo=on`).
|
||||||
// 3. Provide an external URL via the `logoUrl` field.
|
// 3. Provide an external URL via the `logoUrl` field.
|
||||||
// If a file is uploaded it wins over a manually-entered URL.
|
// If a file is uploaded it wins over a manually-entered URL.
|
||||||
let resolvedLogoUrl = str("logoUrl");
|
// Look up the existing logoUrl so we don't accidentally clear it when
|
||||||
|
// the user just edited unrelated fields (the visible URL field is hidden
|
||||||
|
// for stored uploads, so it submits empty in that case).
|
||||||
|
const existing = await db.shopSettings.findUnique({
|
||||||
|
where: { shopDomain: session.shop },
|
||||||
|
select: { logoUrl: true },
|
||||||
|
});
|
||||||
|
const submittedLogoUrl = str("logoUrl");
|
||||||
const removeLogo = bool("removeLogo");
|
const removeLogo = bool("removeLogo");
|
||||||
const logoFile = form.get("logoFile");
|
const logoFile = form.get("logoFile");
|
||||||
const hasUpload =
|
const hasUpload =
|
||||||
logoFile && typeof logoFile === "object" && "size" in logoFile && (logoFile as File).size > 0;
|
logoFile && typeof logoFile === "object" && "size" in logoFile && (logoFile as File).size > 0;
|
||||||
|
|
||||||
|
let resolvedLogoUrl = submittedLogoUrl || existing?.logoUrl || "";
|
||||||
|
|
||||||
if (removeLogo && !hasUpload) {
|
if (removeLogo && !hasUpload) {
|
||||||
await deleteStoredLogo(session.shop);
|
await deleteStoredLogo(session.shop);
|
||||||
resolvedLogoUrl = "";
|
resolvedLogoUrl = "";
|
||||||
|
|||||||
Reference in New Issue
Block a user