how to image upload shopify app using remix and typescript.
i am fresher for creating shopify app. i need upload image shopify app using remix and typescript. i have code for file upload related. when i am image upload in my custom app then image upload but when i am check backend side content in file then showing message “1.png Processing error” when debugging and check image uploaded related three step is required 1) upload 2)processing 3)ready in this step first step upload is working but second step and thired step not working. i have no idea for this related. if anyone have solution. so please tell me. i will share my code and image get error.
import React, { useCallback, useEffect, useState, useRef } from "react";
import { json } from "@remix-run/node";
import { useActionData, useNavigation, useSubmit } from "@remix-run/react";
import {
Page,
Layout,
Card,
Button,
BlockStack,
Box,
InlineStack,
DropZone,
LegacyStack,
Thumbnail,
Text,
} from "@shopify/polaris";
import { authenticate } from "../shopify.server";
import type { ActionFunctionArgs, LoaderFunctionArgs } from "@remix-run/node";
export const loader = async ({ request }: LoaderFunctionArgs) => {
await authenticate.admin(request);
return null;
};
export const action = async ({ request }: ActionFunctionArgs) => {
const { admin } = await authenticate.admin(request);
const color = ["Red", "Orange", "Yellow", "Green"][
Math.floor(Math.random() * 4)
];
const requestBody = await request.text();
const formData = new URLSearchParams(requestBody);
const name = formData.get("filename");
const type = formData.get("filetype");
const size = formData.get("filesize");
const files = [
{
name: name,
type: type,
size: size,
},
];
const prepareFiles = (files: { name: string | null; type: string | null; size: string | null; }[]) =>
files.map((file) => ({
filename: file.name,
mimeType: file.type,
resource: file.type?.includes("image") ? "IMAGE" : "FILE",
fileSize: file.size?.toString(),
httpMethod: "POST",
}));
const preparedFiles = prepareFiles(files);
const uploadFileResponse = await admin.graphql(
`#graphql
mutation stagedUploadsCreate($input: [StagedUploadInput!]!) {
stagedUploadsCreate(input: $input) {
stagedTargets {
resourceUrl
url
parameters {
name
value
}
}
userErrors {
field
message
}
}
}
`,
{ variables: { input: preparedFiles } },
);
const uplodeFileJson = await uploadFileResponse.json();
const resourceurl = uplodeFileJson.data.stagedUploadsCreate.stagedTargets[0].resourceUrl;
const fileCreateResponse = await admin.graphql(
`#graphql
mutation fileCreate($files: [FileCreateInput!]!) {
fileCreate(files: $files) {
files {
alt
createdAt
fileStatus
fileErrors {
code
details
message
}
preview {
image {
url
}
status
__typename
}
... on GenericFile {
id
}
... on Video {
id
}
}
userErrors {
code
field
message
}
}
}`,
{
variables: {
files: {
alt: "Image",
contentType: "IMAGE",
originalSource: resourceurl,
},
},
},
);
const fileCreateJson = await fileCreateResponse.json();
return ({
stagedUpload: uplodeFileJson,
fileCreate: fileCreateJson,
resourceurl: resourceurl
});
};
export default function Index() {
const nav = useNavigation();
const actionData = useActionData();
const submit = useSubmit();
const isLoading = ["loading", "submitting"].includes(nav.state) && nav.formMethod === "POST";
useEffect(() => {
if (actionData) {
shopify.toast.show("Product created");
}
}, [actionData]);
const [files, setFiles] = useState<File[]>([]);
const inputRef = useRef<HTMLInputElement>(null);
const handleDropZoneDrop = useCallback(
async (dropFiles: File[], acceptedFiles: File[], rejectedFiles: File[]) => {
if (acceptedFiles.length) {
setFiles((prevFiles) => [...prevFiles, ...acceptedFiles]);
for (const file of acceptedFiles) {
console.log(file.name);
console.log(file.size);
console.log(file.type);
}
}
},
[],
);
const validImageTypes = ["image/gif", "image/jpeg", "image/png"];
const fileUpload = !files.length && <DropZone.FileUpload />;
const uploadedFiles = files.length > 0 && (
<div style={{ padding: "0" }}>
<LegacyStack vertical>
{files.map((file, index) => (
<LegacyStack alignment="center" key={index}>
<Thumbnail
size="small"
alt={file.name}
source={
validImageTypes.includes(file.type)
? window.URL.createObjectURL(file)
: ""
}
/>
<div>
{file.name}{" "}
<Text variant="bodySm" as="p">
{file.size} bytes
</Text>
</div>
</LegacyStack>
))}
</LegacyStack>
</div>
);
const generateProduct = () => {
const filename = files[0]?.name;
const filetype = files[0]?.type;
const filesize = files[0]?.size;
submit({ filename, filetype, filesize }, { replace: true, method: "POST" });
};
return (
<Page>
<BlockStack gap="500">
<Layout>
<Layout.Section>
<Card>
<InlineStack gap="300">
<DropZone onDrop={handleDropZoneDrop}>
{uploadedFiles}
{fileUpload}
</DropZone>
<Button loading={isLoading} onClick={generateProduct}>
Generate a product
</Button>
</InlineStack>
</Card>
</Layout.Section>
</Layout>
</BlockStack>
</Page>
);
};
i will share some screenshot. when i am image upload.
enter image description here
enter image description here
mohit vamja is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.