-
SummaryA linting error I am getting- Here is the component- "use client"
import { useState, Fragment, useRef } from "react";
import { Dialog, Button, Loading, Input, EmailEditor, Select } from "@repo/ui";
import Image from "next/image";
import { IconBugOff } from "@repo/icon/tabler";
import { useForm, SubmitHandler, Controller } from "react-hook-form";
import toast from "react-hot-toast";
import { SignaturePad, SignatureCanvasRef } from "@siamf/react-signature-pad";
import { useUpload } from "@repo/blob";
//Essentials
import { keywords, formats } from "@/components/email-template/email-form-data";
//Types
import { ReceiptFormInput } from "@/server/receipt/input/receipt.input";
//Trpc
import { trpc } from "@/trpc/client";
//Interface
import { TReceipt } from "@/server/receipt/output/receipt.output";
interface Props {
open: boolean;
onClose: () => void;
item: TReceipt;
}
const EditReceipt = ({ open, onClose, item }: Props) => {
//State
const [sig, setSig] = useState<boolean>(false);
//Trpc
const utils = trpc.useUtils();
const { data, fetchNextPage, isFetchingNextPage, hasNextPage, isLoading } = trpc.receipt.templates.useInfiniteQuery({
search: "",
limit: 12,
}, {
getNextPageParam: (lastPage) => lastPage.nextCursor,
initialCursor: 1,
enabled: !!open
});
const { mutate, isPending } = trpc.receipt.update.useMutation({
onSuccess: (data) => {
return utils.receipt.list.refetch().finally(() => {
toast.success(data.message);
reset();
onClose();
})
},
onError: (error) => {
toast.error(error.message)
}
});
//State
const [template, setTemplate] = useState<{ templateId: string; previewUrl: string } | null>({ templateId: item.templateId || "", previewUrl: item.previewUrl || "" });
//Upload
const { upload, isUploading } = useUpload({
onError: (error) => {
toast.error(error.message)
}
});
//Form Initializing
const {
register,
handleSubmit,
formState: { errors },
reset,
control
} = useForm<ReceiptFormInput>({
values: {
tmlStr: item?.tmlStr || "",
subject: item?.subject || "",
dateFormat: item?.dateFormat || "",
booleanValue: item?.booleanValue || "",
brandId: item.brandId || ""
}
});
//Ref
const ref = useRef<SignatureCanvasRef>(null);
//Data
const rawData = data?.pages.flatMap(a => a.data);
//Handler
const onSubmit: SubmitHandler<ReceiptFormInput> = async (value) => {
let sigUrl: string;
if (sig) {
const { blob } = await upload(ref.current?.toFile());
sigUrl = blob?.url || ""
} else {
sigUrl = item.signature
}
if (template) {
mutate({
...value,
templateId: template.templateId,
previewUrl: template.previewUrl,
signature: sigUrl,
id: item.id
});
}
}
return (
<Dialog
open={open}
onClose={onClose}
className="w-[740px] md:w-[740px] lsm:w-[600px] msm:w-[500px] sm:w-[420px] xxs:w-[320px]"
>
<Dialog.Header
title="Add a receipt"
onClose={onClose}
className="px-5 py-4"
/>
<hr className="border-stroke-light" />
<Dialog.Body className="px-5 py-4">
{!template &&
<Fragment>
<h4 className="text-xl font-semibold text-strong">Choose Template</h4>
{isLoading &&
<div className="my-6 text-center">
<Loading className="mx-auto" />
<p className="text-grayed">Please wait...</p>
</div>
}
<div className="grid grid-cols-4 md:grid-cols-4 msm:grid-cols-3 xxs:grid-cols-2 gap-x-7 gap-y-10 mt-4">
{rawData?.map((item) => (
<div key={item.id} className="relative cursor-pointer" onClick={() => setTemplate({ previewUrl: item.imageUrl, templateId: item.templateId })}>
<Image src={item.imageUrl} width={595} height={841} alt={item.name} className="border border-solid border-stroke/60 rounded-2xl" />
<h4 className="text-center mt-1.5">{item.name}</h4>
</div>
))}
</div>
{rawData?.length === 0 &&
<div className="text-center">
<IconBugOff className="text-error mx-auto" size={30} />
<h4 className="text-lg font-semibold">No Template Found</h4>
<p className="font-light">No available templates here, please wait to be uploaded some templates</p>
</div>
}
{hasNextPage &&
<div className="mt-10 text-center">
<Button isPending={isFetchingNextPage} onClick={() => fetchNextPage()}>
Load More
</Button>
</div>
}
<Button
className="mt-8"
onClick={() => setTemplate({
previewUrl: item.previewUrl,
templateId: item.templateId
})}
>
Cancel now
</Button>
</Fragment>
}
{template &&
<Fragment>
<button className="text-main underline underline-offset-2" onClick={() => setTemplate(null)}>
Change Template
</button>
<form onSubmit={handleSubmit(onSubmit)} className="mt-6">
<Input
id="subject"
label="Email Subject"
placeholder="Subject"
{...register("subject", { required: "Email subject is required" })}
errorMessage={errors.subject?.message}
/>
<Controller
control={control}
name="tmlStr"
rules={{ required: "Template message is required" }}
render={({ field: { onChange, value } }) => (
<EmailEditor
id="message"
label="Message"
placeholder="Write your message here..."
value={value}
onChange={onChange}
rows={7}
words={keywords}
errorMessage={errors.tmlStr?.message}
/>
)}
/>
{sig &&
<Fragment>
<h4 className="text-base font-medium mb-3 inline-block gap-x-1.5">
<span>Add your signature</span>
<span className="text-main underline underline-offset-2 cursor-pointer select-none" onClick={() => setSig(false)}>(Cancel)</span>
</h4>
<div className="bg-white mt-2 rounded-xl border border-stroke/50 mb-4">
<SignaturePad
canvasProps={{ className: "w-full h-[140px] bg-transparent" }}
ref={ref}
/>
</div>
</Fragment>
}
{!sig &&
<div className="">
<h4 className="text-base font-medium mb-3 inline-block gap-x-1.5">
<span>Previously added signature</span>{" "}
<span className="text-main underline underline-offset-2 cursor-pointer select-none" onClick={() => setSig(true)}>(Click here to change)</span>
</h4>
<Image src={item.signature} width={200} height={120} alt="Signature" />
</div>
}
<h4 className="text-lg font-medium mb-5 mt-6">Placeholder Settings</h4>
<Controller
control={control}
name="dateFormat"
render={({ field: { onChange, value } }) => (
<Select
label="Date Format"
placeholder="Choose a date formate for rendering date"
onChange={onChange}
value={value}
options={formats}
/>
)}
/>
<Controller
control={control}
name="booleanValue"
render={({ field: { onChange, value } }) => (
<Select
label="Boolean Value"
placeholder="Choose a value for boolean field"
onChange={onChange}
value={value}
options={[
{ value: "on/of", label: "On/Off" },
{ value: "yes/no", label: "Yes/No" }
]}
/>
)}
/>
<Button type="submit" isPending={isPending || isUploading}>
Update Now
</Button>
</form>
</Fragment>
}
</Dialog.Body>
</Dialog>
);
};
export default EditReceipt;I am not calling ref during render time. Its on a |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 10 replies
-
|
Hi, shouldn't the linter point at the "offending" line of code? I wonder if this could be a bug in the React Compiler linter. Got a repository to look at? |
Beta Was this translation helpful? Give feedback.
-
|
Although I didn't understand the message, but probably you are asking the line number of code where it arising the error or you want to get a repository to solve the problem. If your questions is this, then yea its providing the offending line number- from my above component, you will see a const onSubmit: SubmitHandler<ReceiptFormInput> = async (value) => {
let sigUrl: string;
if (sig) {
const { blob } = await upload(ref.current?.toFile());
sigUrl = blob?.url || ""
} else {
sigUrl = item.signature
}
if (template) {
mutate({
...value,
templateId: template.templateId,
previewUrl: template.previewUrl,
signature: sigUrl,
id: item.id
});
}
}from this handler I am reading a ref value- const { blob } = await upload(ref.current?.toFile());So react compiler throwing error here by saying- |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
|
Were you guys able to resolve this? I am having a similar problem const inputRef = useRef<HTMLInputElement>(null);
const trpc = useTRPC();
const queryClient = useQueryClient();
const createMutation = useMutation(
trpc.apiKey.create.mutationOptions({
onError: err => {
toast.error('Failed to create API Key', { description: err.message });
},
onSuccess: () => {
toast.success('API key created');
void queryClient.invalidateQueries({ queryKey: trpc.apiKey.pathKey() });
inputRef.current?.focus();
},
}),
);
const form = useForm({
...apiKeyCreateFormOptions,
onSubmit: async ({ value }) => {
createMutation.mutate({ name: value.name });
form.reset();
},
});And here is the lint error: |
Beta Was this translation helpful? Give feedback.

I created the issue on React. And it was resolved by the React team. Next.js already merged a PR in their canary release.
Just need to wait for the next release.