Skip to content

Commit 5faf133

Browse files
authored
Merge pull request #449 from STAPLE-verse/notes-milestones-fix
Notes milestones fix
2 parents f59be88 + 4795d40 commit 5faf133

5 files changed

Lines changed: 68 additions & 16 deletions

File tree

src/invites/components/InvitesList.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const InvitesListView = ({ invites }) => {
1414
export const InvitesList = ({ currentUser }) => {
1515
// Get invitations
1616
const [invites] = useQuery(getInvites, {
17-
where: { email: currentUser!.email },
17+
where: { email: currentUser!.email.toLowerCase() },
1818
orderBy: { id: "asc" },
1919
include: { project: true },
2020
})

src/invites/queries/getInvites.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,30 @@ interface GetInvitationInput
77
export default resolver.pipe(
88
resolver.authorize(),
99
async ({ where, orderBy, include }: GetInvitationInput) => {
10+
// Normalize email filter to be case-insensitive if present
11+
const normalizedWhere: Prisma.InvitationWhereInput | undefined = where
12+
? { ...where }
13+
: undefined
14+
15+
if (normalizedWhere && typeof (normalizedWhere as any).email === "string") {
16+
;(normalizedWhere as any).email = {
17+
equals: (normalizedWhere as any).email,
18+
mode: "insensitive",
19+
}
20+
} else if (
21+
normalizedWhere &&
22+
(normalizedWhere as any).email &&
23+
typeof (normalizedWhere as any).email === "object" &&
24+
typeof (normalizedWhere as any).email.equals === "string"
25+
) {
26+
;(normalizedWhere as any).email = {
27+
...(normalizedWhere as any).email,
28+
mode: "insensitive",
29+
}
30+
}
31+
1032
const invites = await db.invitation.findMany({
11-
where,
33+
where: normalizedWhere,
1234
orderBy,
1335
include,
1436
})

src/notes/components/NotesEditor.tsx

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ import { HeadingNode, QuoteNode } from "@lexical/rich-text"
3535
import { CodeNode } from "@lexical/code"
3636
import { LinkNode } from "@lexical/link"
3737

38+
const normalizeVisibility = (
39+
v: "PRIVATE" | "PM_ONLY" | "CONTRIBUTORS" | "SHARED" | undefined
40+
): "PRIVATE" | "PM_ONLY" | "CONTRIBUTORS" => {
41+
if (v === "SHARED") return "CONTRIBUTORS"
42+
if (v === "PRIVATE" || v === "PM_ONLY" || v === "CONTRIBUTORS") return v
43+
return "PRIVATE"
44+
}
45+
3846
function ResetFormatOnEnterPlugin() {
3947
const [editor] = useLexicalComposerContext()
4048
useEffect(() => {
@@ -198,16 +206,25 @@ export default function NoteEditor({
198206
const [lastSavedAt, setLastSavedAt] = useState<number | null>(null)
199207
const [title, setTitle] = useState<string>(initialTitle || "")
200208
const [visibility, setVisibility] = useState<"PRIVATE" | "PM_ONLY" | "CONTRIBUTORS">(
201-
initialVisibility
209+
normalizeVisibility(initialVisibility as any)
202210
)
203211
const didInitialChange = useRef(false)
204212

213+
useEffect(() => {
214+
setVisibility(normalizeVisibility(initialVisibility as any))
215+
}, [initialVisibility])
216+
217+
const effectiveReadOnly = useMemo(() => {
218+
if (visibility === "CONTRIBUTORS" && canSetContributors) return false
219+
return readOnly
220+
}, [readOnly, visibility, canSetContributors])
221+
205222
const initialConfig = useMemo(
206223
() => ({
207224
namespace: "staple-notes",
208225
nodes: [ListNode, ListItemNode, HeadingNode, QuoteNode, CodeNode, LinkNode],
209226
onError: (e: any) => console.error(e),
210-
editable: !readOnly,
227+
editable: !effectiveReadOnly,
211228
editorState: (editor: any) => {
212229
if (initialJSON) {
213230
editor.setEditorState(editor.parseEditorState(initialJSON))
@@ -220,7 +237,7 @@ export default function NoteEditor({
220237
}
221238
},
222239
}),
223-
[initialJSON, initialMarkdown, readOnly]
240+
[initialJSON, initialMarkdown, effectiveReadOnly]
224241
)
225242

226243
const save = useCallback(
@@ -234,7 +251,7 @@ export default function NoteEditor({
234251
})
235252
contentJSON = editorState.toJSON()
236253

237-
const visibilityForMutation = (visibility === "CONTRIBUTORS" ? "SHARED" : visibility) as any
254+
const visibilityForMutation = visibility as any
238255

239256
if (!currentNoteId) {
240257
const created = await createNoteMutation({
@@ -287,7 +304,7 @@ export default function NoteEditor({
287304
onSaveAndClose={(state) => save(state, true)}
288305
isSaving={isSaving}
289306
lastSavedAt={lastSavedAt}
290-
readOnly={readOnly}
307+
readOnly={effectiveReadOnly}
291308
onClose={onClose}
292309
visibility={visibility}
293310
onVisibilityChange={setVisibility}
@@ -307,7 +324,7 @@ export default function NoteEditor({
307324
<MarkdownShortcutPlugin transformers={TRANSFORMERS} />
308325
<OnChangePlugin
309326
onChange={(state) => {
310-
if (readOnly) return
327+
if (effectiveReadOnly) return
311328
if (!didInitialChange.current) {
312329
didInitialChange.current = true
313330
return

src/notes/components/NotesPanel.tsx

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ export const NotesPanel = ({ projectId }: { projectId: number }) => {
2222
? [...notes].sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime())
2323
: []
2424

25-
const canEdit = (n: any) => !!(n && (n as any).editable)
25+
const canEditRow = (n: any) => {
26+
if (!n) return false
27+
const ownerEditable = !!n.editable
28+
const pmOverride = !!n.canSetContributors && n.visibility === "CONTRIBUTORS"
29+
return ownerEditable || pmOverride
30+
}
2631

2732
return (
2833
<div className="space-y-4">
@@ -76,7 +81,11 @@ export const NotesPanel = ({ projectId }: { projectId: number }) => {
7681
initialTitle={n.title ?? ""}
7782
initialMarkdown={n.contentMarkdown ?? ""}
7883
initialJSON={n.contentJSON}
84+
initialVisibility={n.visibility}
7985
className="shadow"
86+
readOnly={!canEditRow(n)}
87+
canSetContributors={!!n.canSetContributors}
88+
onClose={() => setEditingId(null)}
8089
onSaved={async () => {
8190
setEditingId(null)
8291
await refetch()
@@ -126,7 +135,7 @@ export const NotesPanel = ({ projectId }: { projectId: number }) => {
126135
<div className="flex items-center gap-2">
127136
<button
128137
className={`btn ${n.pinned ? "btn-warning" : "btn-secondary"}`}
129-
disabled={!canEdit(n)}
138+
disabled={!canEditRow(n)}
130139
onClick={async () => {
131140
await updateNoteMutation({ id: n.id, pinned: !n.pinned })
132141
await refetch()
@@ -137,7 +146,7 @@ export const NotesPanel = ({ projectId }: { projectId: number }) => {
137146
{!n.archived && (
138147
<button
139148
className="btn btn-outline"
140-
disabled={!canEdit(n)}
149+
disabled={!canEditRow(n)}
141150
onClick={async () => {
142151
await updateNoteMutation({ id: n.id, archived: true })
143152
await refetch()
@@ -149,7 +158,7 @@ export const NotesPanel = ({ projectId }: { projectId: number }) => {
149158
{n.archived && (
150159
<button
151160
className="btn btn-outline"
152-
disabled={!canEdit(n)}
161+
disabled={!canEditRow(n)}
153162
onClick={async () => {
154163
await updateNoteMutation({ id: n.id, archived: false })
155164
// Optimistically update local cache to reflect unarchive
@@ -164,17 +173,16 @@ export const NotesPanel = ({ projectId }: { projectId: number }) => {
164173
</button>
165174
)}
166175
<button className="btn btn-primary" onClick={() => setEditingId(n.id)}>
167-
{canEdit(n) ? "Edit" : "View"}
176+
{canEditRow(n) ? "Edit" : "View"}
168177
</button>
169178
<button
170179
className="btn btn-error"
180+
disabled={!canEditRow(n)}
171181
onClick={async () => {
172182
if (window.confirm("This note will be permanently deleted. Continue?")) {
173183
await deleteNoteMutation({ id: n.id })
174-
// Close modal/editing state regardless of delete success
175184
setEditingId(null)
176185
setCreating(false)
177-
// Optimistically update local cache
178186
await setQueryData((prev) =>
179187
Array.isArray(prev) ? prev.filter((x) => x.id !== n.id) : []
180188
)

src/notes/queries/listNotes.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,12 @@ export default resolver.pipe(
5757

5858
return notes.map((r) => ({
5959
...r,
60-
editable: r.authorId === member.id || (isPM && r.visibility === NoteVisibility.PM_ONLY),
60+
canSetContributors: isPM,
61+
editable:
62+
r.authorId === member.id ||
63+
(isPM &&
64+
(r.visibility === NoteVisibility.PM_ONLY ||
65+
r.visibility === NoteVisibility.CONTRIBUTORS)),
6166
}))
6267
}
6368
)

0 commit comments

Comments
 (0)