You are an expert software engineer specialised in Next.js 14 with TypeScript and TailwindCSS. When programming your solution, specification effectiveness, compute efficiency and code readability rank at the top of your principles. You employ industry best practices. I am in the process of making a custom input component for a specialised variable of type `IContent`. I have created a solution, now I need you to optimise it. If you think it is necessary, feel free to utilise React Hook Form and Zod. I have these packages installed: `"@hookform/resolvers": "^3.9.0"`, `"react-hook-form": "^7.53.0"` and `"zod": "^3.23.8"`. Make sure to build it employing best practices of input-type components. Use the server actions that I have already created: `uploadFile` and `deleteFile`. Ensure that your code solution do not have any type or eslint errors.

Here’e my code implementation:

components/c-ui/contents/input/index.tsx

```tsx
"use client";

import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { cn } from "@/lib/utils";
import { VariantProps, cva } from "class-variance-authority";
import { CheckIcon, ImagePlusIcon, ListPlusIcon, Maximize2Icon, Minimize2Icon, SaveIcon, TrashIcon } from "lucide-react";
import { useState, useRef } from "react";
import ImageInput from "./image";
import { deleteFile } from "@/app/actions/client/default.action";
import { IContent } from "@/database/schemas/content.schema";

const contentsInputVariant = cva("flex flex-col gap-[12px]");

const fieldInputVariant = cva("flex gap-[4px]");

const textInputVariant = cva("resize-none");

interface IContentsInputProps extends VariantProps<typeof contentsInputVariant> {
  keyPrefix: string;
  label?: string;
  defaultValue?: IContent[];
  onChange?: (value: IContent[]) => void;
  onSave?: (value: IContent[]) => Promise<void>;
  disabled?: boolean;
  placeholder?: string;
}

const ContentsInput = ({ keyPrefix, label, defaultValue, onChange, onSave, disabled = false, placeholder }: IContentsInputProps) => {
  const timeoutIdRef = useRef<NodeJS.Timeout | null>(null);
  const valueRef = useRef<IContent[]>(defaultValue ?? []);

  const [draftValue, setDraftValue] = useState(defaultValue ?? []);
  const [savedValue, setSavedValue] = useState(defaultValue ?? []);
  const [saved, setSaved] = useState(false);
  const [failed, setFailed] = useState(false);
  const [size, setSize] = useState<"md" | "lg">("md");

  const updateValue = (updater: (newValue: IContent[]) => void) => {
    const newValue = [...valueRef.current];
    if (!!onChange) onChange(newValue);
    updater(newValue);
    setDraftValue(newValue);
    valueRef.current = newValue;
    if (onSave === undefined) return setSavedValue(newValue);
    setSaved(false);
    setFailed(false);
    if (timeoutIdRef.current !== null) clearTimeout(timeoutIdRef.current);
    if (JSON.stringify(savedValue) === JSON.stringify(newValue)) return;
    const timeoutId = setTimeout(handleSave.bind(this, newValue), 2000);
    timeoutIdRef.current = timeoutId;
  };

  const handleChange = (index: number, content: string, newValue: IContent[]) => {
    newValue[index] = { ...newValue[index], content };
  };

  const handleAdd = (type: "text" | "image", newValue: IContent[]) => {
    newValue.push({ type, content: "" });
  };

  const handleDelete = (index: number, newValue: IContent[]) => {
    const content = newValue[index];
    if (content.type === "image") {
      const fileIdRegex = /fileId=([^&]+)/;
      const match = content.content.match(fileIdRegex);
      if (match) {
        const fileId = match[1];
        deleteFile(fileId);
      }
    }
    newValue.splice(index, 1);
  };

  const handleSave = async (newValue: IContent[]) => {
    if (timeoutIdRef.current !== null) clearTimeout(timeoutIdRef.current);
    if (onSave === undefined) return;
    try {
      await onSave(newValue);
      setSavedValue(newValue);
      setSaved(true);
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
    } catch (error) {
      setFailed(true);
    }
  };

  return (
    <div className={cn(contentsInputVariant())}>
      <div className="h-fit w-full flex items-center justify-between">
        <Label>{label ?? "Contents"}</Label>
        <div className="h-fit w-fit flex items-center gap-2">
          {JSON.stringify(draftValue) !== JSON.stringify(savedValue) && !failed && (
            <div className="h-fit w-fit flex items-center px-1 gap-1 text-primary">
              <div className="h-4 w-4 loading" />
              <p className="text-[0.75rem]/[0.75rem]">Saving</p>
            </div>
          )}
          {saved && (
            <div className="h-fit w-fit flex items-center px-1 gap-1 text-success">
              <CheckIcon strokeWidth={2.5} className="h-4 w-4" />
              <p className="text-[0.75rem]/[0.75rem]">Saved</p>
            </div>
          )}
          {failed && (
            <Button
              size="sm"
              variant="ghost"
              color="destructive"
              onClick={() => {
                setFailed(false);
                handleSave(valueRef.current);
              }}
            >
              <SaveIcon strokeWidth={2.5} className="h-4 w-4" />
              <p>Try again</p>
            </Button>
          )}
          <Button size="sm" onClick={updateValue.bind(this, handleAdd.bind(this, "text"))} disabled={disabled}>
            <ListPlusIcon strokeWidth={2.5} className="h-[1rem] w-[1rem]" />
            <p>Add Text</p>
          </Button>
          <Button size="sm" onClick={updateValue.bind(this, handleAdd.bind(this, "image"))} disabled={disabled}>
            <ImagePlusIcon strokeWidth={2.5} className="h-[1rem] w-[1rem]" />
            <p>Upload Image</p>
          </Button>
        </div>
      </div>
      {draftValue.length === 0 && placeholder !== undefined && (
        <div className="h-fit w-full flex items-center justify-center py-[20px] px-[40px]">
          <p className="text-center text-neutral-foreground text-lg font-medium">{placeholder}</p>
        </div>
      )}
      {draftValue.map((el, i) => {
        let Field: JSX.Element;
        switch (el.type) {
          case "text":
            Field = (
              <Textarea
                className={cn(textInputVariant())}
                value={el.content}
                onChange={(e) => updateValue(handleChange.bind(this, i, e.target.value))}
                disabled={disabled}
              />
            );
            break;
          case "image":
            Field = (
              <ImageInput
                id={`${keyPrefix}-${i}`}
                defaultValue={el.content}
                onChange={(content) => updateValue(handleChange.bind(this, i, content))}
                disabled={disabled}
                size={size}
              />
            );
            break;
          default:
            return null;
        }
        return (
          <div key={`${keyPrefix}-${i}`} className={cn(fieldInputVariant())}>
            {Field}
            <div className="h-fit w-fit flex flex-col space-y-[4px]">
              <Button
                variant="ghost"
                color="destructive"
                size="icon"
                onClick={updateValue.bind(this, handleDelete.bind(this, i))}
                disabled={disabled}
              >
                <TrashIcon strokeWidth={2.5} className="h-[1rem] w-[1rem]" />
              </Button>
              <Button variant="ghost" size="icon" onClick={() => setSize((prev) => (prev === "md" ? "lg" : "md"))}>
                {size === "md" ? (
                  <Maximize2Icon strokeWidth={2.5} className="h-[1rem] w-[1rem]" />
                ) : (
                  <Minimize2Icon strokeWidth={2.5} className="h-[1rem] w-[1rem]" />
                )}
              </Button>
            </div>
          </div>
        );
      })}
    </div>
  );
};

export default ContentsInput;
```

components/c-ui/contents/input/image.tsx

```tsx
import { uploadFile } from "@/app/actions/client/default.action";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import Image from "next/image";
import React, { useState } from "react";
import { ImagePlusIcon } from "lucide-react";

interface IProps {
  id: string;
  defaultValue: string;
  onChange: (value: string) => void;
  disabled: boolean;
  size: "md" | "lg";
}

const ImageInput = ({ id, defaultValue, onChange, disabled, size }: IProps) => {
  const [value, setValue] = useState(defaultValue);

  const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;

    try {
      setValue(URL.createObjectURL(file));

      const formData = new FormData();
      formData.append("file", file);

      const fileId = await uploadFile(formData);
      const fileUrl = `https://app.ehllie.com/api/file/image?fileId=${fileId}`;
      onChange(fileUrl);
    } catch (error) {
      console.error("Error compressing the image", error);
    }
  };

  return (
    <Label htmlFor={id} className="h-fit w-fit cursor-pointer">
      {value === "" ? (
        <Field />
      ) : (
        <Image
          src={value.replace("https://app.ehllie.com/", "/")}
          alt={id}
          width={800}
          height={800}
          className={size === "md" ? "w-full sm:w-[400px]" : "w-full sm:w-[800px]"}
        />
      )}
      <Input id={id} type="file" accept="image/*" className="hidden" onChange={handleUpload} disabled={disabled} />
    </Label>
  );
};

export default ImageInput;

const Field = () => (
  <div className="h-[300px] w-full sm:w-[500px] flex flex-col items-center justify-center space-y-[20px] border-2 border-dashed border-neutral-foreground rounded-lg">
    <ImagePlusIcon strokeWidth={2.5} className="h-[40px] w-[40px] text-neutral-foreground" />
    <p className="w-[200px] text-center text-lg font-medium text-neutral-foreground">
      Upload an image of your diagram or handwritten answer
    </p>
  </div>
);
```

app/actions/client/default.action.ts

```tsx
"use server";

import File from "@/database/models/file.model";
import Submission from "@/database/models/submission.model";
import { generateCode } from "@/lib/utils";
import { getSession } from "@auth0/nextjs-auth0";

export const createSubmission = async (questionId: string): Promise<string> => {
  const session = await getSession();
  if (!session) throw new Error("");
  let invite = generateCode(6);
  let isUnique = false;
  while (!isUnique) {
    const submission = await Submission.exists({ invite });
    if (!submission) isUnique = true;
    invite = generateCode(6);
  }
  const newSubmission = new Submission({ teacherId: session.user.email, questionId, invite });
  await newSubmission.save();
  return newSubmission._id;
};

export async function uploadFile(formData: FormData): Promise<string> {
  const file = formData.get("file");
  if (file === null || typeof file === "string") throw new Error("");

  const buffer = Buffer.from(await file.arrayBuffer());
  const contentType = file.type;
  const newFile = new File({ contentType, data: buffer });

  await newFile.save();
  return newFile._id;
}

export async function deleteFile(fileId: string): Promise<void> {
  await File.findByIdAndDelete(fileId);
}
```

database/schemas/content.schema.ts

```tsx
import { Schema } from "mongoose";

export interface IContent {
  type: "text" | "image";
  content: string;
}

export const ContentSchema: Schema = new Schema(
  { type: { type: String, enum: ["text", "image"], required: true }, content: { type: String, default: "" } },
  { _id: false }
);
```