Skip to content

Commit 2659072

Browse files
committed
feat: add import files frontend routing and file input
1 parent 21b892e commit 2659072

3 files changed

Lines changed: 72 additions & 2 deletions

File tree

frontend/src/Puffnote.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ function NotesApp() {
1717
activeNote,
1818
setActiveIndex,
1919
createNote,
20+
handleImportNotes,
2021
updateNoteContent,
2122
renameNote,
2223
deleteNote,
@@ -36,7 +37,7 @@ function NotesApp() {
3637
onToggle={() => setSidebarOpen(!sidebarOpen)}
3738
/>
3839
<main className={`flex-1 transition-[margin] duration-300 ease min-h-screen w-full relative ${sidebarOpen ? "ml-[250px]" : "ml-0"}`}>
39-
<Options />
40+
<Options onImportNotes={handleImportNotes} />
4041

4142
<div className="h-full pt-16 md:pt-4">
4243
<Editor activeNote={activeNote} updateNoteContent={updateNoteContent} />

frontend/src/components/Options.tsx

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,34 @@
1-
export function Options() {
1+
import { useRef, type ChangeEvent } from "react";
2+
3+
type Props = {
4+
onImportNotes: (file: File) => Promise<void> | void;
5+
};
6+
7+
export function Options({ onImportNotes }: Props) {
8+
const fileInputRef = useRef<HTMLInputElement | null>(null);
9+
10+
function handleImportButtonClick() {
11+
if (!fileInputRef.current) return;
12+
fileInputRef.current.value = "";
13+
fileInputRef.current.click();
14+
}
15+
16+
function handleFileChange(event: ChangeEvent<HTMLInputElement>) {
17+
const file = event.target.files?.[0];
18+
if (!file) return;
19+
20+
void onImportNotes(file);
21+
event.target.value = "";
22+
}
23+
224
return (
325
<div className="absolute top-4 right-5 z-50 md:right-15">
26+
<input
27+
ref={fileInputRef}
28+
type="file"
29+
className="hidden"
30+
onChange={handleFileChange}
31+
/>
432
<div className="flex items-center gap-3">
533
<button
634
type="button"
@@ -10,6 +38,7 @@ export function Options() {
1038
</button>
1139
<button
1240
type="button"
41+
onClick={handleImportButtonClick}
1342
className="inline-flex items-center rounded-xl border border-border bg-card/95 px-4 py-2 text-sm font-medium text-foreground shadow-lg backdrop-blur transition hover:bg-accent"
1443
>
1544
Import notes

frontend/src/hooks/useNotes.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,30 @@ async function deleteNoteRequest(id: string, getToken: GetToken): Promise<void>
104104
}
105105
}
106106

107+
async function importNotes(file: File, getToken: GetToken): Promise<void> {
108+
const url = BASEURL + "/notes/imports";
109+
const formData = new FormData();
110+
formData.append("file", file);
111+
112+
const headers = await authHeaders(getToken);
113+
114+
try {
115+
const response = await fetch(url, {
116+
method: "POST",
117+
headers,
118+
credentials: "include",
119+
body: formData,
120+
});
121+
122+
if (!response.ok) {
123+
throw new Error("request failed");
124+
}
125+
} catch (err) {
126+
console.error(err);
127+
throw err;
128+
}
129+
}
130+
107131
export function useNotes() {
108132
const { isLoaded, isSignedIn, getToken } = useAuth();
109133
const [notes, setNotes] = useState<Note[]>([]);
@@ -211,6 +235,21 @@ export function useNotes() {
211235
[getToken, notes]
212236
);
213237

238+
const handleImportNotes = useCallback(
239+
async (file: File) => {
240+
try {
241+
await importNotes(file, getToken);
242+
243+
const loadedNotes = await loadNotes(getToken);
244+
setNotes(loadedNotes);
245+
setActiveIndex(Math.max(loadedNotes.length - 1, 0));
246+
} catch (err) {
247+
console.error(err);
248+
}
249+
},
250+
[getToken]
251+
);
252+
214253
const activeNote = notes[activeIndex] ?? null;
215254

216255
return {
@@ -219,6 +258,7 @@ export function useNotes() {
219258
activeNote,
220259
setActiveIndex,
221260
createNote,
261+
handleImportNotes,
222262
updateNoteContent,
223263
renameNote,
224264
deleteNote,

0 commit comments

Comments
 (0)