Skip to content

Commit

Permalink
frontend: Implement uploading file
Browse files Browse the repository at this point in the history
  • Loading branch information
pbzweihander committed May 13, 2024
1 parent 28f6539 commit 32fb980
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 100 deletions.
37 changes: 18 additions & 19 deletions frontend/src/components/LeftNavLogin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,24 @@ export default function LeftNavLogin() {
Login
</button>
<dialog ref={modalRef} className="modal">
<form
className="form-control modal-box"
onSubmit={handleSubmit(onSubmit)}
>
<label className="label label-text">Password</label>
<input
type="password"
className="input input-bordered w-full"
required
{...register("password")}
/>
<input
type="submit"
className="btn btn-primary mt-4"
value="Login"
disabled={isLoginLoading}
/>
{error && <div className="mt-5 text-error">{error.message}</div>}
</form>
<div className="form-control modal-box">
<form onSubmit={handleSubmit(onSubmit)}>
<label className="label label-text">Password</label>
<input
type="password"
className="input input-bordered w-full"
required
{...register("password")}
/>
<input
type="submit"
className="btn btn-primary mt-4"
value="Login"
disabled={isLoginLoading}
/>
{error && <div className="mt-5 text-error">{error.message}</div>}
</form>
</div>
<form method="dialog" className="modal-backdrop">
<button>close</button>
</form>
Expand Down
14 changes: 13 additions & 1 deletion frontend/src/components/RightNav.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
import { useIsAuthed } from "../queries/auth";
import { useSetting } from "../queries/setting";
import RightNavSetting from "./RightNavSetting";
import RightNavUpload from "./RightNavUpload";

export default function RightNav() {
const { data: setting } = useSetting();
const isAuthed = useIsAuthed() ?? false;

return (
<div className="h-full p-4">
{setting && <RightNavSetting setting={setting} />}
{isAuthed && (
<>
<div className="mb-4">
{setting && <RightNavSetting setting={setting} />}
</div>
<div>
<RightNavUpload />
</div>
</>
)}
</div>
);
}
83 changes: 42 additions & 41 deletions frontend/src/components/RightNavSetting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,53 +30,54 @@ export default function RightNavSetting({
return (
<>
<button
className="flex items-center"
onClick={() => {
modalRef.current?.showModal();
}}
>
<Cog6ToothIcon className="h-10 w-10" />
<Cog6ToothIcon className="mr-3 inline h-10 w-10" />
<span className="text-lg">Settings</span>
</button>
<dialog ref={modalRef} className="modal">
<form
className="form-control modal-box"
onSubmit={handleSubmit(onSubmit)}
>
<label className="label label-text">User name</label>
<input
type="text"
className="input input-bordered w-full"
{...register("userName")}
/>
<label className="label label-text">User description</label>
<textarea
className="textarea textarea-bordered w-full"
{...register("userDescription")}
/>
<label className="label label-text">Instance description</label>
<textarea
className="textarea textarea-bordered w-full"
{...register("instanceDescription")}
/>
<label className="label label-text">Maintainer name</label>
<input
type="text"
className="input input-bordered w-full"
{...register("maintainerName")}
/>
<label className="label label-text">Maintainer email</label>
<input
type="email"
className="input input-bordered w-full"
{...register("maintainerEmail")}
/>
<input
type="submit"
className="btn btn-primary mt-4"
value="Save"
disabled={isLoading}
/>
{error && <div className="mt-5 text-error">{error.message}</div>}
</form>
<div className="form-control modal-box">
<form onSubmit={handleSubmit(onSubmit)}>
<label className="label label-text">User name</label>
<input
type="text"
className="input input-bordered w-full"
{...register("userName")}
/>
<label className="label label-text">User description</label>
<textarea
className="textarea textarea-bordered w-full"
{...register("userDescription")}
/>
<label className="label label-text">Instance description</label>
<textarea
className="textarea textarea-bordered w-full"
{...register("instanceDescription")}
/>
<label className="label label-text">Maintainer name</label>
<input
type="text"
className="input input-bordered w-full"
{...register("maintainerName")}
/>
<label className="label label-text">Maintainer email</label>
<input
type="email"
className="input input-bordered w-full"
{...register("maintainerEmail")}
/>
<input
type="submit"
className="btn btn-primary mt-4"
value="Save"
disabled={isLoading}
/>
{error && <div className="mt-5 text-error">{error.message}</div>}
</form>
</div>
<form method="dialog" className="modal-backdrop">
<button>close</button>
</form>
Expand Down
74 changes: 74 additions & 0 deletions frontend/src/components/RightNavUpload.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { PlusIcon } from "@heroicons/react/24/outline";
import { useRef } from "react";
import { SubmitHandler, useForm } from "react-hook-form";

import { useFileUploadMutation } from "../queries/file";

// import { PostFileQuery } from "../queries/file";

interface UploadForm {
files: FileList;
alt?: string;
}

export default function RightNavUpload() {
const modalRef = useRef<HTMLDialogElement>(null);
const { register, handleSubmit } = useForm<UploadForm>();
const {
mutate: upload,
isLoading,
error,
} = useFileUploadMutation(() => {
modalRef.current?.close();
});

const onSubmit: SubmitHandler<UploadForm> = (data) => {
if (!data.files) {
return;
}
const file = data.files[0];

upload({ file, mediaType: file.type, alt: data.alt });
};

return (
<>
<button
className="flex items-center"
onClick={() => {
modalRef.current?.showModal();
}}
>
<PlusIcon className="mr-3 inline h-10 w-10" />
<span className="text-lg">Upload</span>
</button>
<dialog ref={modalRef} className="modal">
<div className="form-control modal-box">
<form onSubmit={handleSubmit(onSubmit)}>
<input
type="file"
className="file-input file-input-bordered mb-4 w-full"
required
{...register("files")}
/>
<textarea
className="textarea textarea-bordered mb-4 w-full"
placeholder="Alt text..."
{...register("alt")}
/>
<input
type="submit"
className="btn btn-primary"
value="Upload"
disabled={isLoading}
/>
{error && <div className="mt-5 text-error">{error.message}</div>}
</form>
</div>
<form method="dialog" className="modal-backdrop">
<button>close</button>
</form>
</dialog>
</>
);
}
7 changes: 5 additions & 2 deletions frontend/src/pages/login/LogInIndex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ export function LogInIndexPage() {

return (
<div className="relative flex h-full w-full">
<div className="h-full w-full overflow-y-scroll">
<div className="h-full w-full overflow-y-scroll py-10">
{(notes ?? []).map((note) => (
<div className={`chat chat-${note.user != null ? "start" : "end"}`}>
<div
key={note.id}
className={`chat chat-${note.user != null ? "start" : "end"}`}
>
{note.user && (
<div className="chat-header">
{note.user.name != null ? (
Expand Down
73 changes: 36 additions & 37 deletions frontend/src/pages/logout/Initialize.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,43 +19,42 @@ export default function InitializePage() {

return (
<dialog className="modal modal-open">
<form
className="form-control modal-box"
onSubmit={handleSubmit(onSubmit)}
>
<h2 className="text-xl font-bold">Initialize instance</h2>
<label className="label label-text">Instance name</label>
<input
type="text"
className="input input-bordered w-full"
required
{...register("instanceName")}
/>
<label className="label label-text">User handle</label>
<input
type="text"
className="input input-bordered w-full"
autoComplete="username"
placeholder="admin"
required
{...register("userHandle")}
/>
<label className="label label-text">User password</label>
<input
type="password"
className="input input-bordered w-full"
required
autoComplete="new-password"
{...register("userPassword")}
/>
<input
type="submit"
className="btn btn-primary mt-4"
value="Initialize"
disabled={isLoading}
/>
{error && <div className="text-error mt-5">{error.message}</div>}
</form>
<div className="form-control modal-box">
<form onSubmit={handleSubmit(onSubmit)}>
<h2 className="text-xl font-bold">Initialize instance</h2>
<label className="label label-text">Instance name</label>
<input
type="text"
className="input input-bordered w-full"
required
{...register("instanceName")}
/>
<label className="label label-text">User handle</label>
<input
type="text"
className="input input-bordered w-full"
autoComplete="username"
placeholder="admin"
required
{...register("userHandle")}
/>
<label className="label label-text">User password</label>
<input
type="password"
className="input input-bordered w-full"
required
autoComplete="new-password"
{...register("userPassword")}
/>
<input
type="submit"
className="btn btn-primary mt-4"
value="Initialize"
disabled={isLoading}
/>
{error && <div className="mt-5 text-error">{error.message}</div>}
</form>
</div>
</dialog>
);
}
47 changes: 47 additions & 0 deletions frontend/src/queries/file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { useContext } from "react";
import { useMutation } from "react-query";

import { MutationRet } from ".";
import { AccessKeyContext } from "../contexts/auth";
import { throwError } from "../dto";

export interface PostFileQuery {
file: File;
mediaType: string;
alt?: string;
}

export function useFileUploadMutation(
onSuccess: () => void,
): MutationRet<PostFileQuery> {
const [accessKey] = useContext(AccessKeyContext);

return useMutation(
async (payload) => {
const headers: HeadersInit = {
"content-type": "application/octet-stream",
};
if (accessKey.length > 0) {
headers["authorization"] = `Bearer ${accessKey}`;
}
const resp = await fetch(
`/api/file?mediaType=${payload.mediaType}${
payload.alt ? "&alt=" + payload.alt : ""
}`,
{
method: "POST",
headers,
body: payload.file,
},
);
if (!resp.ok) {
await throwError(resp);
}
},
{
onSuccess: () => {
onSuccess();
},
},
);
}

0 comments on commit 32fb980

Please sign in to comment.