Skip to content

Commit 380ece8

Browse files
authored
feat: add validation when updating/creating notes that at least one label must be added (#359)
feat: add validation when updating/creating notes that at least one label must be added
1 parent 9f81668 commit 380ece8

File tree

2 files changed

+29
-1
lines changed

2 files changed

+29
-1
lines changed

src/components/NoteManager/components/NewNote.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,27 @@ type NewNoteProps = {
2020

2121
export const NewNote = ({ version, onCancel, onSave, selectionStart, selectionEnd }: NewNoteProps) => {
2222
const [noteContentError, setNoteContentError] = useState<string | null>(null);
23+
const [noteLabelsError, setNoteLabelsError] = useState<string | null>(null);
2324
const [labels, setLabels] = useState<string[]>(["local"]);
2425

2526
const latestOnCancel = useLatestCallback(onCancel);
2627
const latestOnSave = useLatestCallback(onSave);
2728

29+
const handleLabelsChange = useCallback((nextLabels: string[]) => {
30+
setLabels(nextLabels);
31+
if (nextLabels.length > 0) {
32+
setNoteLabelsError(null);
33+
}
34+
}, []);
35+
2836
const handleCancelClick = useCallback(() => {
2937
latestOnCancel.current();
3038
}, [latestOnCancel]);
3139

3240
const handleSaveClick = useCallback(() => {
3341
const noteContent = textAreaRef.current?.value ?? "";
42+
setNoteContentError(null);
43+
setNoteLabelsError(null);
3444

3545
const mathValidationError = validateMath(noteContent);
3646
if (mathValidationError) {
@@ -41,6 +51,10 @@ export const NewNote = ({ version, onCancel, onSave, selectionStart, selectionEn
4151
setNoteContentError("Note content cannot be empty");
4252
return;
4353
}
54+
if (labels.length === 0) {
55+
setNoteLabelsError("Select at least one label");
56+
return;
57+
}
4458

4559
latestOnSave.current({ noteContent, labels });
4660
}, [latestOnSave, labels]);
@@ -56,7 +70,7 @@ export const NewNote = ({ version, onCancel, onSave, selectionStart, selectionEn
5670
noteDirty,
5771
currentVersionLink,
5872
handleCancelClick,
59-
handleNoteLabelsChange: setLabels,
73+
handleNoteLabelsChange: handleLabelsChange,
6074
handleSaveClick,
6175
originalVersionLink,
6276
selectionStart,
@@ -83,6 +97,7 @@ export const NewNote = ({ version, onCancel, onSave, selectionStart, selectionEn
8397
/>
8498
{noteContentError ? <div className="validation-message">{noteContentError}</div> : null}
8599
<NoteLayout.Labels />
100+
{noteLabelsError ? <div className="validation-message">{noteLabelsError}</div> : null}
86101
<div className="actions gap-2">
87102
<div className="fill" />
88103
<Button variant="tertiary" data-testid={"cancel-button"} onClick={handleCancelClick} size="sm">

src/components/NoteManager/components/Note.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export function Note({ ref, note, active = false, sectionTitles, onEditNote, onD
3636
});
3737

3838
const [noteContentError, setNoteContentError] = useState("");
39+
const [noteLabelsError, setNoteLabelsError] = useState("");
3940
const { metadata } = useMetadataContext();
4041
const { version } = useVersionContext();
4142
const { getHashFromLocationParams } = useGetLocationParamsToHash();
@@ -46,6 +47,7 @@ export function Note({ ref, note, active = false, sectionTitles, onEditNote, onD
4647
const content = textAreaRef.current?.value ?? "";
4748
const mathValidationError = validateMath(content);
4849
setNoteContentError("");
50+
setNoteLabelsError("");
4951

5052
if (mathValidationError) {
5153
setNoteContentError(mathValidationError);
@@ -57,6 +59,11 @@ export function Note({ ref, note, active = false, sectionTitles, onEditNote, onD
5759
return;
5860
}
5961

62+
if (noteDirty.labels.length === 0) {
63+
setNoteLabelsError("Select at least one label");
64+
return;
65+
}
66+
6067
noteDirty.content = content;
6168

6269
onEditNote(note, noteDirty);
@@ -70,10 +77,14 @@ export function Note({ ref, note, active = false, sectionTitles, onEditNote, onD
7077
setIsEditing(true);
7178
setNoteDirty({ ...note.original });
7279
setNoteContentError("");
80+
setNoteLabelsError("");
7381
}, [note, isEditable]);
7482

7583
const handleNoteLabelsChange = useCallback((labels: string[]) => {
7684
setNoteDirty((prevNoteDirty) => ({ ...prevNoteDirty, labels }));
85+
if (labels.length > 0) {
86+
setNoteLabelsError("");
87+
}
7788
}, []);
7889

7990
const handleDeleteClick = useCallback(() => {
@@ -82,6 +93,7 @@ export function Note({ ref, note, active = false, sectionTitles, onEditNote, onD
8293

8394
const handleCancelClick = useCallback(() => {
8495
setNoteContentError("");
96+
setNoteLabelsError("");
8597
setIsEditing(false);
8698
}, []);
8799

@@ -284,6 +296,7 @@ export function Note({ ref, note, active = false, sectionTitles, onEditNote, onD
284296
<NoteLayout.TextArea className={noteContentError ? "error" : ""} ref={textAreaRef} />
285297
{noteContentError ? <div className="validation-message">{noteContentError}</div> : null}
286298
<NoteLayout.Labels />
299+
{noteLabelsError ? <div className="validation-message">{noteLabelsError}</div> : null}
287300
<div className="actions gap-2">
288301
<Button variant="ghost" intent="destructive" size="sm" onClick={handleDeleteClick}>
289302
Delete

0 commit comments

Comments
 (0)