91b148c271
CI / test (push) Has been cancelled
Symptom: clicking + Add time would insert the new entry sorted into
the list, hiding it among the existing rows. Editing an existing
row's hour/minute/AM-PM moved the row mid-keystroke.
Both behaviors made the user lose track of what they were editing.
The list now only sorts at save time (which the backend already
canonicalizes via setWakeTimes()). New entries land at the end,
edits stay in place. Two regression tests pin this:
- + Add appends; the new row is the last DOM row even when its
minutes-of-day are smaller than an existing entry.
- Editing a row's hour from 9 to 1 keeps the row at the same
index (would have moved to index 0 under the old sort-on-edit).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 line
14 KiB
JavaScript
1 line
14 KiB
JavaScript
import{B as e,E as t,H as n,K as r,R as i,_ as a,d as o,dt as s,f as c,g as l,j as u,k as d,m as f,p,pt as m,s as h,t as g,u as _,v,z as y}from"./_plugin-vue_export-helper-DRLwVS0w.js";import{a as b,d as x,f as S,i as C,o as w,p as T,s as E}from"./index-DK_JsCTY.js";import{i as D,n as O,r as ee,t as k}from"./BaseBottomSheet-DsLKl74W.js";import{t as te}from"./PullToRefresh-D9_uAhZQ.js";import{t as A}from"./DevicePicker-xvlGTaxv.js";var j={class:`approve-card`},M=[`src`,`alt`],N={class:`approve-card__body`},P={class:`approve-card__from`},F={class:`approve-card__date`},I={key:0,class:`approve-card__status`},L={class:`approve-card__actions`},ne=g(v({__name:`ApproveCard`,props:{item:{}},emits:[`updated`],setup(e,{emit:t}){let i=e,u=t,g=b(),v=D(),x=n(!1),S=n(!1),C=n([]),w=_(()=>new Date(i.item.sharedAt).toLocaleDateString(void 0,{month:`short`,day:`numeric`,year:`numeric`}));async function T(){x.value=!1,S.value=!0;try{u(`updated`,await g.approveShared(i.item.id,C.value))}finally{S.value=!1,C.value=[]}}async function E(){S.value=!0;try{u(`updated`,await g.declineShared(i.item.id))}finally{S.value=!1}}return(t,n)=>(d(),f(h,null,[o(`div`,j,[o(`img`,{src:e.item.thumbnailUrl,alt:`Photo from ${e.item.sharedBy}`,class:`approve-card__thumb`,loading:`lazy`},null,8,M),o(`div`,N,[o(`p`,P,[n[3]||=l(`From `,-1),o(`strong`,null,m(e.item.sharedBy),1)]),o(`p`,F,m(w.value),1),e.item.status===`pending`?p(``,!0):(d(),f(`div`,I,[o(`span`,{class:s([`approve-card__badge`,`approve-card__badge--${e.item.status}`])},m(e.item.status),3)])),o(`div`,L,[e.item.status===`pending`||e.item.status===`declined`?(d(),c(O,{key:0,variant:`primary`,size:`sm`,disabled:S.value,onClick:n[0]||=e=>x.value=!0},{default:y(()=>[l(m(e.item.status===`declined`?`Add anyway`:`Add to frame`),1)]),_:1},8,[`disabled`])):p(``,!0),e.item.status===`pending`||e.item.status===`approved`?(d(),c(O,{key:1,variant:`ghost`,size:`sm`,disabled:S.value,onClick:E},{default:y(()=>[l(m(e.item.status===`approved`?`Remove`:`Decline`),1)]),_:1},8,[`disabled`])):p(``,!0)])])]),a(A,{modelValue:x.value,"onUpdate:modelValue":n[1]||=e=>x.value=e,devices:r(v).devices,selected:C.value,uploading:S.value,"confirm-label":`Add to frames`,"onUpdate:selected":n[2]||=e=>C.value=e,onConfirm:T},null,8,[`modelValue`,`devices`,`selected`,`uploading`])],64))}}),[[`__scopeId`,`data-v-6d3dd8b4`]]),R={class:`share-sheet__field`},z=[`onKeydown`],B={key:0,class:`share-sheet__error`},V={key:1,class:`share-sheet__success`},re=g(v({__name:`ShareSheet`,props:{modelValue:{type:Boolean},imageId:{}},emits:[`update:modelValue`],setup(t,{emit:r}){let i=t,s=b(),u=n(``),h=n(!1),g=n(``),_=n(``);async function v(){if(g.value=``,_.value=``,u.value.trim()){h.value=!0;try{await s.shareImage(i.imageId,u.value.trim()),_.value=`Invite sent to ${u.value.trim()}`,u.value=``}catch(e){g.value=e instanceof Error?e.message:`Failed to send`}finally{h.value=!1}}}return(n,r)=>(d(),c(k,{"model-value":t.modelValue,label:`Share photo`,"onUpdate:modelValue":r[1]||=e=>n.$emit(`update:modelValue`,e)},{default:y(()=>[r[2]||=o(`h2`,{class:`share-sheet__title`},`Share with someone`,-1),r[3]||=o(`p`,{class:`share-sheet__sub`},`They'll get an email and can add it to their frame.`,-1),o(`div`,R,[e(o(`input`,{"onUpdate:modelValue":r[0]||=e=>u.value=e,type:`email`,class:`share-sheet__input`,placeholder:`their@email.com`,autocomplete:`email`,onKeydown:S(T(v,[`prevent`]),[`enter`])},null,40,z),[[x,u.value]])]),g.value?(d(),f(`p`,B,m(g.value),1)):p(``,!0),_.value?(d(),f(`p`,V,m(_.value),1)):p(``,!0),a(O,{variant:`primary`,class:`share-sheet__btn`,disabled:h.value||!u.value.trim(),onClick:v},{default:y(()=>[l(m(h.value?`Sending…`:`Send invite`),1)]),_:1},8,[`disabled`])]),_:1},8,[`model-value`]))}}),[[`__scopeId`,`data-v-24296e7b`]]),ie={class:`library`},ae={class:`library__header`},oe={class:`library__tabs`,role:`tablist`},se=[`aria-selected`,`onClick`],ce={key:0,class:`library__loading`},le={key:0,class:`library__empty`},ue={key:1,class:`library__grid`},de={class:`library__thumb`},fe=[`src`,`alt`],pe={class:`library__thumb-actions`},me=[`aria-label`,`title`,`onClick`],he=[`aria-label`,`disabled`,`onClick`],ge={key:0,width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"aria-hidden":`true`},_e={key:1,width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"aria-hidden":`true`},ve=[`aria-label`,`onClick`],ye=[`onClick`],be={key:0,class:`library__approvals`},xe=[`aria-label`,`onClick`],Se={key:1,class:`library__locks`},Ce=[`aria-label`,`onClick`],we={width:`10`,height:`10`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"aria-hidden":`true`},Te={key:0,d:`M7 11V7a5 5 0 0 1 10 0v4`},Ee={key:1,d:`M7 11V7a5 5 0 0 1 9.9-1`},De={class:`library__subtabs`,role:`tablist`},Oe=[`aria-selected`,`onClick`],ke={key:0,class:`library__loading`},Ae={key:1,class:`library__shared-empty`},H={class:`library__empty-title`},je={class:`library__empty-sub`},Me={key:2,class:`library__shared-list`},Ne={key:3,class:`library__pagination`},Pe=[`disabled`],Fe={class:`library__page-info`},Ie=[`disabled`],Le={class:`library__sheet-actions`},U=g(v({__name:`LibraryView`,setup(e){let g=E(),v=b(),x=D(),S=ee(),T=C(),A=w(),j=[{id:`all`,label:`All`},{id:`mine`,label:`Mine`},{id:`shared`,label:`Shared`}];function M(e){return j.some(t=>t.id===e)?e:`all`}let N=n(M(A.query.tab));i(()=>A.query.tab,e=>{let t=M(e);t!==N.value&&(N.value=t,t===`shared`&&B(F.value))});let P=[{id:`pending`,label:`Pending`},{id:`approved`,label:`Approved`},{id:`declined`,label:`Declined`}],F=n(`pending`),I=n([]),L=n(!1),R=n(1),z=n(1);async function B(e,t=1){L.value=!0;try{let n=await v.fetchSharedImages(e,t);I.value=n.items,R.value=n.page,z.value=n.totalPages}finally{L.value=!1}}function V(e){F.value=e,B(e,1)}function U(e){B(F.value,e)}function Re(e){let t=I.value.findIndex(t=>t.id===e.id);t!==-1&&(I.value[t]=e)}t(()=>{v.fetchImages(),x.fetchDevices(),v.fetchPendingCount(),N.value===`shared`&&B(F.value)});function ze(){let e=document.createElement(`input`);e.type=`file`,e.accept=`image/jpeg,image/png,image/webp,image/gif`,e.onchange=()=>{let t=e.files?.[0];t&&(S.init(t),g.push(`/upload`))},e.click()}function Be(){return window.scrollY===0}async function Ve(){await Promise.all([v.fetchImages({silent:!0}),v.fetchPendingCount(),x.fetchDevices({silent:!0}),N.value===`shared`?B(F.value,R.value):Promise.resolve()])}let W=_(()=>v.images),G=n(!1),K=n(null);function He(e){K.value=e,G.value=!0}let q=n(null);async function J(e,t){if(!q.value){q.value=e.id;try{await S.initEdit(e,t),g.push(`/upload`)}catch{T.show(`Could not load photo for editing`,`error`)}finally{q.value=null}}}function Y(e){if(e.cropOrientation)return e.cropOrientation;let t=e.cropParams;return!t?.natW||!t?.natH?null:t.natW>=t.natH?`landscape`:`portrait`}function X(e){let t=Y(e);if(!t)return null;for(let n of e.approvedDeviceIds){let e=x.devices.find(e=>e.id===n);if(e&&e.orientation!==t)return e}return null}async function Ue(e,t){try{t.lockedImageId===e?await x.unlockImage(t.id):await x.lockImage(t.id,e)}catch{T.show(`Failed to update lock`,`error`)}}async function We(e,t,n){try{await v.setApproval(e,t,n)}catch{T.show(`Failed to update frame approval`,`error`)}}let Z=n(!1),Q=n(null),$=n(!1);function Ge(e){Q.value=e,Z.value=!0}async function Ke(){if(Q.value){$.value=!0;try{await v.deleteImage(Q.value),Z.value=!1,T.show(`Photo deleted`,`success`)}catch{T.show(`Delete failed`,`error`)}finally{$.value=!1}}}return(e,t)=>(d(),f(`main`,ie,[a(te,{"is-at-top":Be,"on-refresh":Ve},{default:y(()=>[o(`div`,ae,[a(O,{variant:`primary`,class:`library__add-btn`,onClick:ze},{default:y(()=>[...t[5]||=[l(` + Add Photo `,-1)]]),_:1})]),o(`div`,oe,[(d(),f(h,null,u(j,e=>o(`button`,{key:e.id,type:`button`,role:`tab`,"aria-selected":N.value===e.id,class:s([`library__tab`,{"library__tab--active":N.value===e.id}]),onClick:t=>N.value=e.id},m(e.label),11,se)),64))]),r(v).loading?(d(),f(`div`,ce,`Loading…`)):N.value===`shared`?(d(),f(h,{key:2},[o(`div`,De,[(d(),f(h,null,u(P,e=>o(`button`,{key:e.id,type:`button`,role:`tab`,"aria-selected":F.value===e.id,class:s([`library__subtab`,{"library__subtab--active":F.value===e.id}]),onClick:t=>V(e.id)},m(e.label),11,Oe)),64))]),L.value?(d(),f(`div`,ke,`Loading…`)):I.value.length===0?(d(),f(`div`,Ae,[t[13]||=o(`svg`,{width:`48`,height:`48`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.5`,"aria-hidden":`true`},[o(`circle`,{cx:`18`,cy:`5`,r:`3`}),o(`circle`,{cx:`6`,cy:`12`,r:`3`}),o(`circle`,{cx:`18`,cy:`19`,r:`3`}),o(`line`,{x1:`8.59`,y1:`13.51`,x2:`15.42`,y2:`17.49`}),o(`line`,{x1:`15.41`,y1:`6.51`,x2:`8.59`,y2:`10.49`})],-1),o(`p`,H,m(F.value===`pending`?`No pending photos`:F.value===`approved`?`No approved photos`:`No declined photos`),1),o(`p`,je,m(F.value===`pending`?`Photos shared with you will appear here.`:`Photos you've added to a frame will appear here.`),1)])):(d(),f(`div`,Me,[(d(!0),f(h,null,u(I.value,e=>(d(),c(ne,{key:e.id,item:e,onUpdated:Re},null,8,[`item`]))),128))])),z.value>1?(d(),f(`div`,Ne,[o(`button`,{class:`library__page-btn`,disabled:R.value<=1,onClick:t[0]||=e=>U(R.value-1)},`← Prev`,8,Pe),o(`span`,Fe,m(R.value)+` / `+m(z.value),1),o(`button`,{class:`library__page-btn`,disabled:R.value>=z.value,onClick:t[1]||=e=>U(R.value+1)},`Next →`,8,Ie)])):p(``,!0)],64)):(d(),f(h,{key:1},[W.value.length===0?(d(),f(`div`,le,[...t[6]||=[o(`svg`,{width:`48`,height:`48`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.5`,"aria-hidden":`true`},[o(`rect`,{x:`3`,y:`3`,width:`18`,height:`18`,rx:`2`}),o(`circle`,{cx:`8.5`,cy:`8.5`,r:`1.5`}),o(`polyline`,{points:`21,15 16,10 5,21`})],-1),o(`p`,{class:`library__empty-title`},`No photos yet`,-1),o(`p`,{class:`library__empty-sub`},`Tap "+ Add Photo" above to upload your first one.`,-1)]])):(d(),f(`div`,ue,[(d(!0),f(h,null,u(W.value,e=>(d(),f(`div`,{key:e.id,class:`library__item`},[o(`div`,de,[o(`img`,{src:e.thumbnailUrl,alt:e.originalFilename,class:`library__img`,loading:`lazy`},null,8,fe),o(`div`,pe,[X(e)?(d(),f(`button`,{key:0,class:`library__action-btn library__action-btn--warn`,type:`button`,"aria-label":`Crop orientation does not match ${X(e).name}; tap to re-crop`,title:`Cropped ${Y(e)}, but ${X(e).name} is set to ${X(e).orientation}.`,onClick:t=>J(e,X(e).id)},[...t[7]||=[o(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"aria-hidden":`true`},[o(`path`,{d:`M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z`}),o(`line`,{x1:`12`,y1:`9`,x2:`12`,y2:`13`}),o(`line`,{x1:`12`,y1:`17`,x2:`12.01`,y2:`17`})],-1)]],8,me)):p(``,!0),o(`button`,{class:`library__action-btn`,type:`button`,"aria-label":`Edit ${e.originalFilename}`,disabled:q.value===e.id,onClick:t=>J(e)},[q.value===e.id?(d(),f(`svg`,_e,[...t[9]||=[o(`circle`,{cx:`12`,cy:`12`,r:`10`},null,-1),o(`line`,{x1:`12`,y1:`8`,x2:`12`,y2:`12`},null,-1),o(`line`,{x1:`12`,y1:`16`,x2:`12.01`,y2:`16`},null,-1)]])):(d(),f(`svg`,ge,[...t[8]||=[o(`path`,{d:`M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7`},null,-1),o(`path`,{d:`M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z`},null,-1)]]))],8,he),o(`button`,{class:`library__action-btn`,type:`button`,"aria-label":`Share ${e.originalFilename}`,onClick:t=>He(e.id)},[...t[10]||=[o(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"aria-hidden":`true`},[o(`circle`,{cx:`18`,cy:`5`,r:`3`}),o(`circle`,{cx:`6`,cy:`12`,r:`3`}),o(`circle`,{cx:`18`,cy:`19`,r:`3`}),o(`line`,{x1:`8.59`,y1:`13.51`,x2:`15.42`,y2:`17.49`}),o(`line`,{x1:`15.41`,y1:`6.51`,x2:`8.59`,y2:`10.49`})],-1)]],8,ve),o(`button`,{class:`library__action-btn library__action-btn--danger`,type:`button`,"aria-label":`Delete photo`,onClick:t=>Ge(e.id)},[...t[11]||=[o(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"aria-hidden":`true`},[o(`polyline`,{points:`3 6 5 6 21 6`}),o(`path`,{d:`M19 6l-1 14H6L5 6`}),o(`path`,{d:`M10 11v6M14 11v6`}),o(`path`,{d:`M9 6V4h6v2`})],-1)]],8,ye)])]),r(x).devices.length>0?(d(),f(`div`,be,[(d(!0),f(h,null,u(r(x).devices,t=>(d(),f(`button`,{key:t.id,class:s([`library__approval-chip`,{"library__approval-chip--on":e.approvedDeviceIds.includes(t.id)}]),type:`button`,"aria-label":`${e.approvedDeviceIds.includes(t.id)?`Remove from`:`Add to`} ${t.name}`,onClick:n=>We(e.id,t.id,!e.approvedDeviceIds.includes(t.id))},m(t.name),11,xe))),128))])):p(``,!0),r(x).devices.length>0?(d(),f(`div`,Se,[(d(!0),f(h,null,u(r(x).devices.filter(t=>e.approvedDeviceIds.includes(t.id)),n=>(d(),f(`button`,{key:n.id,class:s([`library__lock-chip`,{"library__lock-chip--on":n.lockedImageId===e.id}]),type:`button`,"aria-label":`${n.lockedImageId===e.id?`Unlock from`:`Lock to`} ${n.name}`,onClick:t=>Ue(e.id,n)},[(d(),f(`svg`,we,[t[12]||=o(`rect`,{x:`3`,y:`11`,width:`18`,height:`11`,rx:`2`,ry:`2`},null,-1),n.lockedImageId===e.id?(d(),f(`path`,Te)):(d(),f(`path`,Ee))])),l(` `+m(n.name),1)],10,Ce))),128))])):p(``,!0)]))),128))]))],64))]),_:1}),K.value===null?p(``,!0):(d(),c(re,{key:0,modelValue:G.value,"onUpdate:modelValue":t[2]||=e=>G.value=e,"image-id":K.value},null,8,[`modelValue`,`image-id`])),a(k,{modelValue:Z.value,"onUpdate:modelValue":t[4]||=e=>Z.value=e,label:`Delete photo`},{default:y(()=>[t[15]||=o(`h2`,{class:`library__sheet-title`},`Delete this photo?`,-1),t[16]||=o(`p`,{class:`library__sheet-sub`},`It will be removed from all frames.`,-1),o(`div`,Le,[a(O,{variant:`secondary`,onClick:t[3]||=e=>Z.value=!1},{default:y(()=>[...t[14]||=[l(`Cancel`,-1)]]),_:1}),a(O,{variant:`destructive`,disabled:$.value,onClick:Ke},{default:y(()=>[l(m($.value?`Deleting…`:`Delete`),1)]),_:1},8,[`disabled`])])]),_:1},8,[`modelValue`])]))}}),[[`__scopeId`,`data-v-d22a9085`]]);export{U as default}; |