11<template >
2- <article :id =" `note-${note.id}-outer`" class =" advising-note-outer w-100" >
2+ <div :id =" `note-${note.id}-outer`" class =" advising-note-outer w-100" >
33 <div
4- :id =" `note-${note.id}-is-closed`"
5- aria-level =" 3"
4+ :id =" `${note.eForm ? 'eForm' : 'note'}-${note.id}-is-closed`"
5+ :aria-controls =" isOpen ? undefined : `note-${note.id}-is-open`"
6+ :aria-expanded =" isOpen ? undefined : false"
67 class =" d-flex w-100"
78 :class =" {
89 'font-size-18': !note.peerAdvisingDepartmentId,
9- 'note-snippet-when-closed': !isOpen
10+ 'cursor-pointer note-snippet-when-closed': !isOpen
1011 }"
11- role =" heading"
12+ :role =" isOpen ? undefined : 'button'"
13+ :tabindex =" isOpen ? undefined : 0"
14+ @click =" onClickOpen"
15+ @keyup.enter =" onClickOpen"
1216 >
1317 <div v-if =" note.isDraft" :id =" `note-${note.id}-is-draft`" class =" d-flex align-center" >
1418 <v-badge
5559 </div >
5660 <section
5761 :id =" `note-${note.id}-is-open`"
58- class =" note-body pb-4 "
62+ class =" note-body"
5963 :class =" {'sr-only': !isOpen}"
6064 >
6165 <div v-if =" (note.subject || note.isDraft) && note.message" class =" open-note-message-container py-3" >
6468 <div v-if =" !note.subject && !note.message && note.eForm" class =" py-3" >
6569 <AdvisingEForm :note =" note " />
6670 </div >
67- <div v-if =" isAuthorDetailsLoaded && !isNil(author) && !author.name && !author.email && !note.eForm" class =" font-size-14 py-3 text-medium-emphasis" >
68- Advisor profile not found
69- <span v-if =" note.legacySource" class =" font-italic" >
70- (note imported from {{ note.legacySource }})
71- </span >
72- </div >
73- <div v-if =" isAuthorDetailsLoaded && author && !note.eForm" class =" py-3" >
74- <div v-if =" author.name || author.email" >
75- <span class =" sr-only" >Note created by </span >
76- <span v-if =" author.uid && author.name" >
77- <router-link
78- v-if =" currentUser.isAdmin && note.peerAdvisingDepartmentId"
79- :id =" `note-${note.id}-link-to-peer-advisor-home`"
80- :to =" `/peer_advisor/${author.uid}/home`"
81- >
82- {{ author.name }}
83- </router-link >
84- <a
85- v-if =" !currentUser.isAdmin || !note.peerAdvisingDepartmentId"
86- :id =" `note-${note.id}-author-name`"
87- :aria-label =" `${author.name} UC Berkeley Directory page (opens in new tab)`"
88- :href =" `https://www.berkeley.edu/directory/results?search-term=${author.name}`"
89- target =" _blank"
90- >
91- {{ author.name }}
92- </a >
93- </span >
94- <span v-if =" !author.uid && author.name" :id =" `note-${note.id}-author-name`" >
95- {{ author.name }}
96- </span >
97- <span v-if =" !author.uid && !author.name && author.email" :id =" `note-${note.id}-author-email`" >
98- {{ author.email }}
99- </span >
100- <span v-if =" author.role || author.title" >
101- - <span :id =" `note-${note.id}-author-role`" >{{ capitalizeAllWords(replace(author.role || author.title, '_', ' ')) }}</span >
102- </span >
103- <span v-if =" note.legacySource" class =" font-italic text-medium-emphasis" >
104- (note imported from {{ note.legacySource }})
105- </span >
106- </div >
107- <div v-if =" note.peerAdvisingDepartmentId" >
108- <span :id =" `note-${note.id}-peer-advising-department`" >{{ peerAdvisingDepartment.name }}</span >
109- <div
110- v-if =" peerAdvisingDepartment.deptName !== peerAdvisingDepartment.name"
111- :id =" `note-${note.id}-university-department-of-peer-advisor`"
112- class =" text-medium-emphasis"
113- >
114- {{ peerAdvisingDepartment.deptName }}
115- </div >
116- </div >
117- <div v-if =" !note.peerAdvisingDepartmentId" class =" text-medium-emphasis" >
118- <div v-for =" (deptName, index) in authorDepartments" :key =" index" >
119- <span :id =" `note-${note.id}-author-dept-${index}`" >{{ deptName }}</span >
120- </div >
121- </div >
122- </div >
123- <div v-if =" note.topics && size(note.topics)" class =" mt-5" >
124- <AdvisingNoteTopics
125- label-class="text-medium-emphasis"
126- :note =" note "
127- read-only
128- />
71+ <div v-if =" !note.eForm && note.legacySource" class =" font-italic text-medium-emphasis" >
72+ (note imported from {{ note.legacySource }})
12973 </div >
74+ <AdvisingNoteTopics
75+ v-if =" note .topics && size (note .topics )"
76+ class="mt-5"
77+ label-class="text-medium-emphasis"
78+ :note =" note "
79+ read-only
80+ />
13081 <div v-if =" note.contactType" class =" mt-5" >
13182 <div class =" font-size-16 font-weight-bold text-medium-emphasis" >Contact Type</div >
13283 <div :id =" `note-${note.id}-contact-type`" >{{ note.contactType }}</div >
14697 />
14798 </div >
14899 </section >
149- <AdvisingNoteComments
150- v-if =" ! note .legacySource || note .eForm "
151- class="border-t-sm py-4"
152- :class =" {' sr-only' : ! isOpen } "
153- :note =" note "
154- />
155100 <AreYouSureModal
156101 v-model =" showConfirmDeleteAttachment "
157102 button-label-confirm="Delete"
161106 >
162107 Are you sure you want to delete the <strong >'{{ attachmentToDelete.displayName }}'</strong > attachment?
163108 </AreYouSureModal >
164- </article >
109+ </div >
165110</template >
166111
167112<script setup>
168- import {computed , onMounted , ref , watch } from ' vue'
169- import {get , isNil , map , orderBy , replace , size } from ' lodash'
113+ import {computed , ref } from ' vue'
114+ import {size } from ' lodash'
170115import {mdiCommentOutline , mdiPaperclip } from ' @mdi/js'
171116import AdvisingEForm from ' @/components/note/eform/AdvisingEForm'
172117import AdvisingNoteAttachments from ' @/components/note/AdvisingNoteAttachments'
173- import AdvisingNoteComments from ' @/components/note/comment/AdvisingNoteComments'
174118import AdvisingNoteTopics from ' @/components/note/AdvisingNoteTopics'
175119import AreYouSureModal from ' @/components/util/AreYouSureModal'
176120import {addAttachments , removeAttachment } from ' @/api/notes'
177- import {alertScreenReader , capitalizeAllWords , oxfordJoin , pluralize } from ' @/lib/utils'
121+ import {alertScreenReader , pluralize } from ' @/lib/utils'
178122import {canUserEditNote , summarizeNoteForAcademicTimeline } from ' @/lib/note.js'
179- import {findPeerAdvisingDepartment , getBoaUserRoles } from ' @/lib/berkeley-department'
180- import {getCalnetProfileByCsid , getCalnetProfileByUid } from ' @/api/user'
181123import {useContextStore } from ' @/stores/context'
182124import {useNoteStore } from ' @/stores/note-edit-session'
183125
@@ -197,6 +139,10 @@ const props = defineProps({
197139 note: {
198140 required: true ,
199141 type: Object
142+ },
143+ onClickOpen: {
144+ required: true ,
145+ type: Function
200146 }
201147})
202148
@@ -205,28 +151,16 @@ const noteStore = useNoteStore()
205151
206152const addAttachmentInputElementId = ` note-${ props .note .id } -choose-file-for-note-attachment`
207153const attachmentToDelete = ref ()
208- const author = ref (get (props .note , ' author' ))
209- const authorDepartments = computed (() => orderBy (map (author .value .departments , ' deptName' )))
210154const currentUser = contextStore .currentUser
211- const isAuthorDetailsLoaded = ref (false )
212155const isUpdatingAttachments = ref (false )
213156const noteSummary = computed (() => {
214157 const note = props .note
215158 const showNoteMessage = props .isOpen && ! note .subject && ! note .peerAdvisingDepartmentId && size (note .message )
216159 return showNoteMessage ? note .message : summarizeNoteForAcademicTimeline (note, ! props .isOpen )
217160})
218- const peerAdvisingDepartment = computed (() => props .note .peerAdvisingDepartmentId ? findPeerAdvisingDepartment (props .note .peerAdvisingDepartmentId ) : undefined )
219161const showConfirmDeleteAttachment = ref (false )
220162const showNoteAttachmentsWidget = computed (() => (! props .note .legacySource && canUserEditNote (props .note , currentUser)) || size (props .note .attachments ))
221163
222- watch (() => props .isOpen , () => {
223- loadAuthorDetails ()
224- })
225-
226- onMounted (() => {
227- loadAuthorDetails ()
228- })
229-
230164const addNoteAttachments = attachments => {
231165 return new Promise (resolve => {
232166 isUpdatingAttachments .value = true
@@ -256,45 +190,6 @@ const confirmedRemoveAttachment = () => {
256190 }
257191}
258192
259- const loadAuthorDetails = () => {
260- const requiresLazyLoad = (
261- props .isOpen &&
262- (
263- ! get (props .note , ' author.name' ) ||
264- ! get (props .note , ' author.role' ) ||
265- get (author .value , ' uid' ) !== get (props .note , ' author.uid' ) ||
266- get (author .value , ' sid' ) !== get (props .note , ' author.sid' )
267- )
268- )
269- if (requiresLazyLoad) {
270- const hasIdentifier = get (props .note , ' author.uid' ) || get (props .note , ' author.sid' )
271- if (hasIdentifier) {
272- const author_uid = props .note .author .uid
273- const callback = data => {
274- author .value = data
275- author .value .role = author .value .role || author .value .title
276- if (! author .value .role && author .value .departments .length ) {
277- author .value .role = oxfordJoin (getBoaUserRoles (author .value .departments [0 ]))
278- }
279- }
280- if (author_uid) {
281- if (author_uid === currentUser .uid ) {
282- callback (currentUser)
283- isAuthorDetailsLoaded .value = true
284- } else {
285- getCalnetProfileByUid (author_uid).then (callback).finally (() => isAuthorDetailsLoaded .value = true )
286- }
287- } else if (props .note .author .sid ) {
288- getCalnetProfileByCsid (props .note .author .sid ).then (callback).finally (() => isAuthorDetailsLoaded .value = true )
289- }
290- } else {
291- isAuthorDetailsLoaded .value = true
292- }
293- } else {
294- isAuthorDetailsLoaded .value = true
295- }
296- }
297-
298193const removeAttachmentByIndex = index => {
299194 attachmentToDelete .value = props .note .attachments [index]
300195 showConfirmDeleteAttachment .value = true
0 commit comments