11import { parseWithZod } from '@conform-to/zod'
2- import { type FileUpload , parseFormData } from '@mjackson/form-data-parser'
2+ import { parseFormData } from '@mjackson/form-data-parser'
33import { createId as cuid } from '@paralleldrive/cuid2'
44import { data , redirect , type ActionFunctionArgs } from 'react-router'
55import { z } from 'zod'
66import { requireUserId } from '#app/utils/auth.server.ts'
77import { prisma } from '#app/utils/db.server.ts'
8- import { uploadHandler } from '#app/utils/file-uploads .server.ts'
8+ import { uploadNoteImage } from '#app/utils/storage .server.ts'
99import {
1010 MAX_UPLOAD_SIZE ,
1111 NoteEditorSchema ,
@@ -20,18 +20,16 @@ function imageHasFile(
2020
2121function imageHasId (
2222 image : ImageFieldset ,
23- ) : image is ImageFieldset & { id : NonNullable < ImageFieldset [ 'id' ] > } {
24- return image . id != null
23+ ) : image is ImageFieldset & { id : string } {
24+ return Boolean ( image . id )
2525}
2626
2727export async function action ( { request } : ActionFunctionArgs ) {
2828 const userId = await requireUserId ( request )
2929
30- const formData = await parseFormData (
31- request ,
32- { maxFileSize : MAX_UPLOAD_SIZE } ,
33- async ( file : FileUpload ) => uploadHandler ( file ) ,
34- )
30+ const formData = await parseFormData ( request , {
31+ maxFileSize : MAX_UPLOAD_SIZE ,
32+ } )
3533
3634 const submission = await parseWithZod ( formData , {
3735 schema : NoteEditorSchema . superRefine ( async ( data , ctx ) => {
@@ -48,16 +46,17 @@ export async function action({ request }: ActionFunctionArgs) {
4846 } )
4947 }
5048 } ) . transform ( async ( { images = [ ] , ...data } ) => {
49+ const noteId = data . id ?? cuid ( )
5150 return {
5251 ...data ,
52+ id : noteId ,
5353 imageUpdates : await Promise . all (
5454 images . filter ( imageHasId ) . map ( async ( i ) => {
5555 if ( imageHasFile ( i ) ) {
5656 return {
5757 id : i . id ,
5858 altText : i . altText ,
59- contentType : i . file . type ,
60- blob : Buffer . from ( await i . file . arrayBuffer ( ) ) ,
59+ objectKey : await uploadNoteImage ( userId , noteId , i . file ) ,
6160 }
6261 } else {
6362 return {
@@ -74,8 +73,7 @@ export async function action({ request }: ActionFunctionArgs) {
7473 . map ( async ( image ) => {
7574 return {
7675 altText : image . altText ,
77- contentType : image . file . type ,
78- blob : Buffer . from ( await image . file . arrayBuffer ( ) ) ,
76+ objectKey : await uploadNoteImage ( userId , noteId , image . file ) ,
7977 }
8078 } ) ,
8179 ) ,
@@ -101,8 +99,9 @@ export async function action({ request }: ActionFunctionArgs) {
10199
102100 const updatedNote = await prisma . note . upsert ( {
103101 select : { id : true , owner : { select : { username : true } } } ,
104- where : { id : noteId ?? '__new_note__' } ,
102+ where : { id : noteId } ,
105103 create : {
104+ id : noteId ,
106105 ownerId : userId ,
107106 title,
108107 content,
@@ -115,7 +114,11 @@ export async function action({ request }: ActionFunctionArgs) {
115114 deleteMany : { id : { notIn : imageUpdates . map ( ( i ) => i . id ) } } ,
116115 updateMany : imageUpdates . map ( ( updates ) => ( {
117116 where : { id : updates . id } ,
118- data : { ...updates , id : updates . blob ? cuid ( ) : updates . id } ,
117+ data : {
118+ ...updates ,
119+ // If the image is new, we need to generate a new ID to bust the cache.
120+ id : updates . objectKey ? cuid ( ) : updates . id ,
121+ } ,
119122 } ) ) ,
120123 create : newImages ,
121124 } ,
0 commit comments