# File request upload

> The public page of a file request link, where anyone with the link sends a file into a folder, with the link's password when it has one.

Source: https://bettersupabase.com/docs/registry/ui-recipes/file-request-upload

{/* Generated by scripts/build-recipes.ts from the example apps. Edit the examples or the script, then run `pnpm recipes`. */}

It loads its data on the server through the block's client; the [drive](https://bettersupabase.com/blocks/drive), [share-links](https://bettersupabase.com/blocks/share-links) blocks must be installed (`npx better-supabase add drive share-links`). Its page on bettersupabase.com is [/recipes/file-request-upload](https://bettersupabase.com/recipes/file-request-upload).

Web, with shadcn components:

```bash
npx shadcn add badge button card empty field input
```

```tsx title="apps/examples/nextjs/src/features/drive/components/file-request-upload.tsx"
/**
 * The public page of a file request link: pick a file and send it into the
 * folder, with the link's password when it has one. The sender never sees what
 * the folder holds.
 */
export function FileRequestUpload({ token }: { token: string }) {
  const t = useExtracted("drive");
  const fieldId = useId();
  const errorMessage = useErrorMessage();
  const [password, setPassword] = useState<"none" | "asked" | "wrong">("none");
  const [sent, setSent] = useState<string | null>(null);

  const form = useActionForm(sendToFileRequest, {
    resetOnSuccess: false,
    onSuccess: (result, element) => {
      if (result.passwordRequired) {
        setPassword((current) => (current === "none" ? "asked" : "wrong"));

        return;
      }

      element.reset();
      setSent(result.name);
    },
  });

  const error = form.error === undefined ? null : errorMessage(form.error);
  const locked = password !== "none";
  const wrongPassword = password === "wrong";

  return (
    <Card data-recipe="file-request-upload">
      <CardHeader>
        <CardTitle>{t("Send files")}</CardTitle>
        <CardDescription>
          {t("Files you send go straight to the folder's owner.")}
        </CardDescription>
      </CardHeader>
      <CardContent>
        {sent === null ? (
          <form {...form.formProps} className="flex flex-col gap-4">
            <input type="hidden" name="token" value={token} />
            <FieldGroup>
              <Field data-invalid={form.fieldErrors["file"] ? true : undefined}>
                <FieldLabel htmlFor={`${fieldId}-file`}>{t("File")}</FieldLabel>
                <Input
                  id={`${fieldId}-file`}
                  name="file"
                  type="file"
                  required
                />
                <FieldDescription>{t("Up to 1 MB per file.")}</FieldDescription>
              </Field>
              {locked ? (
                <Field data-invalid={wrongPassword ? true : undefined}>
                  <FieldLabel htmlFor={`${fieldId}-password`}>
                    {t("Password")}
                  </FieldLabel>
                  <Input
                    id={`${fieldId}-password`}
                    name="password"
                    type="password"
                    required
                    maxLength={200}
                    autoComplete="off"
                  />
                  {wrongPassword ? (
                    <FieldError>
                      {t(
                        "This link needs its password. Check it and try again.",
                      )}
                    </FieldError>
                  ) : null}
                </Field>
              ) : null}
              {error ? <FieldError>{error}</FieldError> : null}
            </FieldGroup>
            <div className="flex justify-end">
              <Button type="submit" disabled={form.pending}>
                {t("Send")}
              </Button>
            </div>
          </form>
        ) : (
          <Empty className="border">
            <EmptyHeader>
              <EmptyMedia variant="icon">
                <CircleCheckIcon />
              </EmptyMedia>
              <EmptyTitle>{t("File sent")}</EmptyTitle>
              <EmptyDescription>{sent}</EmptyDescription>
            </EmptyHeader>
            <EmptyContent>
              <Badge variant="success-light">{t("Received")}</Badge>
              <Button
                variant="outline"
                onClick={() => {
                  form.reset();
                  setSent(null);
                }}
              >
                {t("Send another file")}
              </Button>
            </EmptyContent>
          </Empty>
        )}
      </CardContent>
    </Card>
  );
}
```