2cd558bac3
CI / test (push) Has been cancelled
Both the backend preview endpoint and the frontend cache-buster were preferring lockedImage over currentImage. Locking is a queued override that doesn't take effect until the device's next poll, so showing it on Home before the device has actually pulled it lied about the frame's state. Always use currentImage now. Also: add a primary "+ Add Photo" button at the top of the Library page so users can upload without bouncing back to Home; updates the empty- state copy to point at the new button. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 line
14 KiB
JavaScript
1 line
14 KiB
JavaScript
import{A as e,G as t,L as n,O as r,R as i,T as a,V as o,_ as s,d as c,f as l,ft as u,g as d,h as f,l as p,o as m,p as h,t as g,u as _,ut as v,z as y}from"./_plugin-vue_export-helper-CeYnMxKK.js";import{a as b,d as x,f as S,i as C,o as w,s as T,u as E}from"./index-BGc6BnG_.js";import{i as D,n as O,r as ee,t as k}from"./BaseBottomSheet-vZ7hFF0Y.js";import{t as te}from"./PullToRefresh-DZt-0188.js";import{t as A}from"./DevicePicker-BAb-kxko.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(s({__name:`ApproveCard`,props:{item:{}},emits:[`updated`],setup(e,{emit:n}){let a=e,s=n,g=b(),y=D(),x=o(!1),S=o(!1),C=o([]),w=p(()=>new Date(a.item.sharedAt).toLocaleDateString(void 0,{month:`short`,day:`numeric`,year:`numeric`}));async function T(){x.value=!1,S.value=!0;try{s(`updated`,await g.approveShared(a.item.id,C.value))}finally{S.value=!1,C.value=[]}}async function E(){S.value=!0;try{s(`updated`,await g.declineShared(a.item.id))}finally{S.value=!1}}return(n,a)=>(r(),h(m,null,[_(`div`,j,[_(`img`,{src:e.item.thumbnailUrl,alt:`Photo from ${e.item.sharedBy}`,class:`approve-card__thumb`,loading:`lazy`},null,8,M),_(`div`,N,[_(`p`,P,[a[3]||=f(`From `,-1),_(`strong`,null,u(e.item.sharedBy),1)]),_(`p`,F,u(w.value),1),e.item.status===`pending`?l(``,!0):(r(),h(`div`,I,[_(`span`,{class:v([`approve-card__badge`,`approve-card__badge--${e.item.status}`])},u(e.item.status),3)])),_(`div`,L,[e.item.status===`pending`||e.item.status===`declined`?(r(),c(O,{key:0,variant:`primary`,size:`sm`,disabled:S.value,onClick:a[0]||=e=>x.value=!0},{default:i(()=>[f(u(e.item.status===`declined`?`Add anyway`:`Add to frame`),1)]),_:1},8,[`disabled`])):l(``,!0),e.item.status===`pending`||e.item.status===`approved`?(r(),c(O,{key:1,variant:`ghost`,size:`sm`,disabled:S.value,onClick:E},{default:i(()=>[f(u(e.item.status===`approved`?`Remove`:`Decline`),1)]),_:1},8,[`disabled`])):l(``,!0)])])]),d(A,{modelValue:x.value,"onUpdate:modelValue":a[1]||=e=>x.value=e,devices:t(y).devices,selected:C.value,uploading:S.value,"confirm-label":`Add to frames`,"onUpdate:selected":a[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(s({__name:`ShareSheet`,props:{modelValue:{type:Boolean},imageId:{}},emits:[`update:modelValue`],setup(e,{emit:t}){let n=e,a=b(),s=o(``),p=o(!1),m=o(``),g=o(``);async function v(){if(m.value=``,g.value=``,s.value.trim()){p.value=!0;try{await a.shareImage(n.imageId,s.value.trim()),g.value=`Invite sent to ${s.value.trim()}`,s.value=``}catch(e){m.value=e instanceof Error?e.message:`Failed to send`}finally{p.value=!1}}}return(t,n)=>(r(),c(k,{"model-value":e.modelValue,label:`Share photo`,"onUpdate:modelValue":n[1]||=e=>t.$emit(`update:modelValue`,e)},{default:i(()=>[n[2]||=_(`h2`,{class:`share-sheet__title`},`Share with someone`,-1),n[3]||=_(`p`,{class:`share-sheet__sub`},`They'll get an email and can add it to their frame.`,-1),_(`div`,R,[y(_(`input`,{"onUpdate:modelValue":n[0]||=e=>s.value=e,type:`email`,class:`share-sheet__input`,placeholder:`their@email.com`,autocomplete:`email`,onKeydown:x(S(v,[`prevent`]),[`enter`])},null,40,z),[[E,s.value]])]),m.value?(r(),h(`p`,B,u(m.value),1)):l(``,!0),g.value?(r(),h(`p`,V,u(g.value),1)):l(``,!0),d(O,{variant:`primary`,class:`share-sheet__btn`,disabled:p.value||!s.value.trim(),onClick:v},{default:i(()=>[f(u(p.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(s({__name:`LibraryView`,setup(s){let g=T(),y=b(),x=D(),S=ee(),E=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=o(M(A.query.tab));n(()=>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=o(`pending`),I=o([]),L=o(!1),R=o(1),z=o(1);async function B(e,t=1){L.value=!0;try{let n=await y.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)}a(()=>{y.fetchImages(),x.fetchDevices(),y.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([y.fetchImages(),y.fetchPendingCount(),x.fetchDevices(),N.value===`shared`?B(F.value,R.value):Promise.resolve()])}let W=p(()=>y.images),G=o(!1),K=o(null);function He(e){K.value=e,G.value=!0}let q=o(null);async function J(e,t){if(!q.value){q.value=e.id;try{await S.initEdit(e,t),g.push(`/upload`)}catch{E.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{E.show(`Failed to update lock`,`error`)}}async function We(e,t,n){try{await y.setApproval(e,t,n)}catch{E.show(`Failed to update frame approval`,`error`)}}let Z=o(!1),Q=o(null),$=o(!1);function Ge(e){Q.value=e,Z.value=!0}async function Ke(){if(Q.value){$.value=!0;try{await y.deleteImage(Q.value),Z.value=!1,E.show(`Photo deleted`,`success`)}catch{E.show(`Delete failed`,`error`)}finally{$.value=!1}}}return(n,a)=>(r(),h(`main`,ie,[d(te,{"is-at-top":Be,"on-refresh":Ve},{default:i(()=>[_(`div`,ae,[d(O,{variant:`primary`,class:`library__add-btn`,onClick:ze},{default:i(()=>[...a[5]||=[f(` + Add Photo `,-1)]]),_:1})]),_(`div`,oe,[(r(),h(m,null,e(j,e=>_(`button`,{key:e.id,type:`button`,role:`tab`,"aria-selected":N.value===e.id,class:v([`library__tab`,{"library__tab--active":N.value===e.id}]),onClick:t=>N.value=e.id},u(e.label),11,se)),64))]),t(y).loading?(r(),h(`div`,ce,`Loading…`)):N.value===`shared`?(r(),h(m,{key:2},[_(`div`,De,[(r(),h(m,null,e(P,e=>_(`button`,{key:e.id,type:`button`,role:`tab`,"aria-selected":F.value===e.id,class:v([`library__subtab`,{"library__subtab--active":F.value===e.id}]),onClick:t=>V(e.id)},u(e.label),11,Oe)),64))]),L.value?(r(),h(`div`,ke,`Loading…`)):I.value.length===0?(r(),h(`div`,Ae,[a[13]||=_(`svg`,{width:`48`,height:`48`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.5`,"aria-hidden":`true`},[_(`circle`,{cx:`18`,cy:`5`,r:`3`}),_(`circle`,{cx:`6`,cy:`12`,r:`3`}),_(`circle`,{cx:`18`,cy:`19`,r:`3`}),_(`line`,{x1:`8.59`,y1:`13.51`,x2:`15.42`,y2:`17.49`}),_(`line`,{x1:`15.41`,y1:`6.51`,x2:`8.59`,y2:`10.49`})],-1),_(`p`,H,u(F.value===`pending`?`No pending photos`:F.value===`approved`?`No approved photos`:`No declined photos`),1),_(`p`,je,u(F.value===`pending`?`Photos shared with you will appear here.`:`Photos you've added to a frame will appear here.`),1)])):(r(),h(`div`,Me,[(r(!0),h(m,null,e(I.value,e=>(r(),c(ne,{key:e.id,item:e,onUpdated:Re},null,8,[`item`]))),128))])),z.value>1?(r(),h(`div`,Ne,[_(`button`,{class:`library__page-btn`,disabled:R.value<=1,onClick:a[0]||=e=>U(R.value-1)},`← Prev`,8,Pe),_(`span`,Fe,u(R.value)+` / `+u(z.value),1),_(`button`,{class:`library__page-btn`,disabled:R.value>=z.value,onClick:a[1]||=e=>U(R.value+1)},`Next →`,8,Ie)])):l(``,!0)],64)):(r(),h(m,{key:1},[W.value.length===0?(r(),h(`div`,le,[...a[6]||=[_(`svg`,{width:`48`,height:`48`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.5`,"aria-hidden":`true`},[_(`rect`,{x:`3`,y:`3`,width:`18`,height:`18`,rx:`2`}),_(`circle`,{cx:`8.5`,cy:`8.5`,r:`1.5`}),_(`polyline`,{points:`21,15 16,10 5,21`})],-1),_(`p`,{class:`library__empty-title`},`No photos yet`,-1),_(`p`,{class:`library__empty-sub`},`Tap "+ Add Photo" above to upload your first one.`,-1)]])):(r(),h(`div`,ue,[(r(!0),h(m,null,e(W.value,n=>(r(),h(`div`,{key:n.id,class:`library__item`},[_(`div`,de,[_(`img`,{src:n.thumbnailUrl,alt:n.originalFilename,class:`library__img`,loading:`lazy`},null,8,fe),_(`div`,pe,[X(n)?(r(),h(`button`,{key:0,class:`library__action-btn library__action-btn--warn`,type:`button`,"aria-label":`Crop orientation does not match ${X(n).name}; tap to re-crop`,title:`Cropped ${Y(n)}, but ${X(n).name} is set to ${X(n).orientation}.`,onClick:e=>J(n,X(n).id)},[...a[7]||=[_(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"aria-hidden":`true`},[_(`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`}),_(`line`,{x1:`12`,y1:`9`,x2:`12`,y2:`13`}),_(`line`,{x1:`12`,y1:`17`,x2:`12.01`,y2:`17`})],-1)]],8,me)):l(``,!0),_(`button`,{class:`library__action-btn`,type:`button`,"aria-label":`Edit ${n.originalFilename}`,disabled:q.value===n.id,onClick:e=>J(n)},[q.value===n.id?(r(),h(`svg`,_e,[...a[9]||=[_(`circle`,{cx:`12`,cy:`12`,r:`10`},null,-1),_(`line`,{x1:`12`,y1:`8`,x2:`12`,y2:`12`},null,-1),_(`line`,{x1:`12`,y1:`16`,x2:`12.01`,y2:`16`},null,-1)]])):(r(),h(`svg`,ge,[...a[8]||=[_(`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),_(`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),_(`button`,{class:`library__action-btn`,type:`button`,"aria-label":`Share ${n.originalFilename}`,onClick:e=>He(n.id)},[...a[10]||=[_(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"aria-hidden":`true`},[_(`circle`,{cx:`18`,cy:`5`,r:`3`}),_(`circle`,{cx:`6`,cy:`12`,r:`3`}),_(`circle`,{cx:`18`,cy:`19`,r:`3`}),_(`line`,{x1:`8.59`,y1:`13.51`,x2:`15.42`,y2:`17.49`}),_(`line`,{x1:`15.41`,y1:`6.51`,x2:`8.59`,y2:`10.49`})],-1)]],8,ve),_(`button`,{class:`library__action-btn library__action-btn--danger`,type:`button`,"aria-label":`Delete photo`,onClick:e=>Ge(n.id)},[...a[11]||=[_(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"aria-hidden":`true`},[_(`polyline`,{points:`3 6 5 6 21 6`}),_(`path`,{d:`M19 6l-1 14H6L5 6`}),_(`path`,{d:`M10 11v6M14 11v6`}),_(`path`,{d:`M9 6V4h6v2`})],-1)]],8,ye)])]),t(x).devices.length>0?(r(),h(`div`,be,[(r(!0),h(m,null,e(t(x).devices,e=>(r(),h(`button`,{key:e.id,class:v([`library__approval-chip`,{"library__approval-chip--on":n.approvedDeviceIds.includes(e.id)}]),type:`button`,"aria-label":`${n.approvedDeviceIds.includes(e.id)?`Remove from`:`Add to`} ${e.name}`,onClick:t=>We(n.id,e.id,!n.approvedDeviceIds.includes(e.id))},u(e.name),11,xe))),128))])):l(``,!0),t(x).devices.length>0?(r(),h(`div`,Se,[(r(!0),h(m,null,e(t(x).devices.filter(e=>n.approvedDeviceIds.includes(e.id)),e=>(r(),h(`button`,{key:e.id,class:v([`library__lock-chip`,{"library__lock-chip--on":e.lockedImageId===n.id}]),type:`button`,"aria-label":`${e.lockedImageId===n.id?`Unlock from`:`Lock to`} ${e.name}`,onClick:t=>Ue(n.id,e)},[(r(),h(`svg`,we,[a[12]||=_(`rect`,{x:`3`,y:`11`,width:`18`,height:`11`,rx:`2`,ry:`2`},null,-1),e.lockedImageId===n.id?(r(),h(`path`,Te)):(r(),h(`path`,Ee))])),f(` `+u(e.name),1)],10,Ce))),128))])):l(``,!0)]))),128))]))],64))]),_:1}),K.value===null?l(``,!0):(r(),c(re,{key:0,modelValue:G.value,"onUpdate:modelValue":a[2]||=e=>G.value=e,"image-id":K.value},null,8,[`modelValue`,`image-id`])),d(k,{modelValue:Z.value,"onUpdate:modelValue":a[4]||=e=>Z.value=e,label:`Delete photo`},{default:i(()=>[a[15]||=_(`h2`,{class:`library__sheet-title`},`Delete this photo?`,-1),a[16]||=_(`p`,{class:`library__sheet-sub`},`It will be removed from all frames.`,-1),_(`div`,Le,[d(O,{variant:`secondary`,onClick:a[3]||=e=>Z.value=!1},{default:i(()=>[...a[14]||=[f(`Cancel`,-1)]]),_:1}),d(O,{variant:`destructive`,disabled:$.value,onClick:Ke},{default:i(()=>[f(u($.value?`Deleting…`:`Delete`),1)]),_:1},8,[`disabled`])])]),_:1},8,[`modelValue`])]))}}),[[`__scopeId`,`data-v-a01e5735`]]);export{U as default}; |