diff --git a/src/utils/Helpers.jsx b/src/utils/Helpers.jsx
index 5e33a12..b276778 100644
--- a/src/utils/Helpers.jsx
+++ b/src/utils/Helpers.jsx
@@ -85,9 +85,9 @@ const extractStorageKey = url => {
// replace them with backend proxy URLs (which generate fresh signed URLs on
// each request). Returns the patched HTML, or the original if nothing changed.
const refreshSignedUrlsInHtml = html => {
- console.debug('1. refreshSignedUrlsInHtml', { html })
if (!html) return html
if (
+ !html.includes('dt-data-path') &&
!html.includes('X-Amz-') &&
!html.includes('X-Goog-') &&
!html.includes('sig') &&
@@ -95,22 +95,26 @@ const refreshSignedUrlsInHtml = html => {
) {
return html
}
- console.debug('2. refreshSignedUrlsInHtml: found potential signed URLs, parsing HTML...')
const parser = new DOMParser()
const doc = parser.parseFromString(html, 'text/html')
const imgs = doc.querySelectorAll('img[src]')
let changed = false
- imgs.forEach(async img => {
-
- if (!img.getAttribute('dt-data-path')) {
- // not custom tag, skipping:
- return
- }
+ imgs.forEach(img => {
+ const stablePath = img.getAttribute('dt-data-path')
const src = img.getAttribute('src')
+ let nextSrc = src
- img.setAttribute('src', resolvePhotoURL(src))
- changed = true
+ if (stablePath) {
+ nextSrc = resolvePhotoURL(stablePath)
+ } else if (isCloudSignedUrl(src)) {
+ nextSrc = resolvePhotoURL(extractStorageKey(src))
+ }
+
+ if (nextSrc && nextSrc !== src) {
+ img.setAttribute('src', nextSrc)
+ changed = true
+ }
})
return changed ? doc.body.innerHTML : html
diff --git a/src/views/ChoreEdit/ChoreEdit.jsx b/src/views/ChoreEdit/ChoreEdit.jsx
index a6d0a25..7ac6cd4 100644
--- a/src/views/ChoreEdit/ChoreEdit.jsx
+++ b/src/views/ChoreEdit/ChoreEdit.jsx
@@ -975,7 +975,10 @@ const ChoreEdit = () => {
key={att.file_path || idx}
onClick={() => {
const url = resolvePhotoURL(att.sign || att.file_path)
- const ext = att.file_name?.split('.').pop().toLowerCase()
+ const ext = (att.file_name || '')
+ .split('.')
+ .pop()
+ .toLowerCase()
const isImage = [
'jpg',
'jpeg',
@@ -1031,7 +1034,8 @@ const ChoreEdit = () => {
size='sm'
variant='plain'
color='danger'
- onClick={() => {
+ onClick={event => {
+ event.stopPropagation()
DeleteChoreAttachment(choreId, att.file_path)
.then(() => {
setAttachments(prev =>
@@ -1054,7 +1058,8 @@ const ChoreEdit = () => {
size='sm'
variant='plain'
color='danger'
- onClick={() => {
+ onClick={event => {
+ event.stopPropagation()
setAttachments(prev =>
prev.filter((_, i) => i !== idx),
)
diff --git a/src/views/ChoreEdit/ChoreView.jsx b/src/views/ChoreEdit/ChoreView.jsx
index ffd55fb..0b51fd3 100644
--- a/src/views/ChoreEdit/ChoreView.jsx
+++ b/src/views/ChoreEdit/ChoreView.jsx
@@ -631,7 +631,7 @@ const ChoreView = () => {
mb: 0.5,
}}
>
- asde{chore.name}
+ {chore.name}
{chore.isActive === false && (
diff --git a/src/views/Modals/Inputs/AttachmentBrowserModal.jsx b/src/views/Modals/Inputs/AttachmentBrowserModal.jsx
index 55b1f54..3de68f5 100644
--- a/src/views/Modals/Inputs/AttachmentBrowserModal.jsx
+++ b/src/views/Modals/Inputs/AttachmentBrowserModal.jsx
@@ -34,8 +34,12 @@ function AttachmentBrowserModal({ choreId, isOpen, onClose }) {
if (!isOpen || !choreId) return
setIsLoading(true)
GetChoreAttachments(choreId)
- .then(res => res.json())
+ .then(async res => {
+ if (!res.ok) throw new Error('Failed to fetch attachments')
+ return res.json()
+ })
.then(data => setAttachments(Array.isArray(data) ? data : []))
+ .catch(() => setAttachments([]))
.finally(() => setIsLoading(false))
}, [isOpen, choreId])
@@ -91,7 +95,16 @@ function AttachmentBrowserModal({ choreId, isOpen, onClose }) {
) : (
{attachments.map((attachment, index) => (
-
+
handleAttachmentClick(attachment)}
sx={{ borderRadius: 'sm', gap: 1.5, py: 1 }}
diff --git a/src/views/Modals/Inputs/AttachmentViewerModal.jsx b/src/views/Modals/Inputs/AttachmentViewerModal.jsx
index 741a5ab..317b2f9 100644
--- a/src/views/Modals/Inputs/AttachmentViewerModal.jsx
+++ b/src/views/Modals/Inputs/AttachmentViewerModal.jsx
@@ -92,12 +92,14 @@ function AttachmentViewerModal({ config }) {
component='img'
src={url}
alt={fileName}
+ onClick={() => url && openUrl(url)}
onLoad={() => setImgLoaded(true)}
onError={() => {
setImgLoaded(true)
setImgError(true)
}}
sx={{
+ cursor: url ? 'zoom-in' : 'default',
maxWidth: '100%',
maxHeight: '65vh',
borderRadius: 'md',
diff --git a/src/views/Settings/ProfileSettings.jsx b/src/views/Settings/ProfileSettings.jsx
index 1bb2c2c..27e2f28 100644
--- a/src/views/Settings/ProfileSettings.jsx
+++ b/src/views/Settings/ProfileSettings.jsx
@@ -88,8 +88,7 @@ const ProfileSettings = () => {
formData.append('file', compressedFile, 'profile.jpg')
const response = await apiClient.upload('/users/profile_photo', formData)
if (!response.ok) throw new Error('Upload failed')
- const data = await response.json()
- // const url = resolvePhotoURL(data.url || data.sign)
+ await response.json()
refetchUserProfile() // Refresh user profile to get the new photoURL
showSuccess({
diff --git a/src/views/components/ScanToTask/ScanPanel.jsx b/src/views/components/ScanToTask/ScanPanel.jsx
index 88bf541..855ac07 100644
--- a/src/views/components/ScanToTask/ScanPanel.jsx
+++ b/src/views/components/ScanToTask/ScanPanel.jsx
@@ -21,7 +21,7 @@ import { useScanToTask } from './useScanToTask'
* Flow: capture → (auto) processing → done [calls onTaskExtracted + onClose]
* → error [retake or cancel]
*/
-const ScanPanel = ({ open, onTaskExtracted, onClose }) => {
+const ScanPanel = ({ open, onTaskExtracted, onClose, initialImageUrl }) => {
const {
isNativeScanner,
phase,
@@ -46,12 +46,12 @@ const ScanPanel = ({ open, onTaskExtracted, onClose }) => {
// Start/stop based on open state
useEffect(() => {
if (open) {
- activate()
+ activate(initialImageUrl)
} else {
reset()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [open])
+ }, [open, initialImageUrl])
// Start camera when entering capture phase on web
useEffect(() => {
diff --git a/src/views/components/ScanToTask/useScanToTask.js b/src/views/components/ScanToTask/useScanToTask.js
index 2b5eea4..66b5d95 100644
--- a/src/views/components/ScanToTask/useScanToTask.js
+++ b/src/views/components/ScanToTask/useScanToTask.js
@@ -207,13 +207,22 @@ export function useScanToTask() {
setPhase('capture')
}, [])
- const activate = useCallback(() => {
- setCapturedImage(null)
- setTaskResult(null)
- setErrorMsg('')
- setOcrProgress(0)
- setPhase('capture')
- }, [])
+ const activate = useCallback(
+ (initialImageUrl = null) => {
+ setCapturedImage(initialImageUrl)
+ setTaskResult(null)
+ setErrorMsg('')
+ setOcrProgress(0)
+
+ if (initialImageUrl) {
+ processImage(initialImageUrl, 'browser')
+ return
+ }
+
+ setPhase('capture')
+ },
+ [processImage],
+ )
const reset = useCallback(() => {
stopCamera()
diff --git a/src/views/components/SmartTaskTitleInput.jsx b/src/views/components/SmartTaskTitleInput.jsx
index bd8a9ff..9a66b32 100644
--- a/src/views/components/SmartTaskTitleInput.jsx
+++ b/src/views/components/SmartTaskTitleInput.jsx
@@ -235,8 +235,6 @@ const SmartTaskTitleInput = ({
caretColor: mode === 'dark' ? '#fff' : '#000',
border: 'none',
outline: 'none',
- border: 'none',
- outline: 'none',
}}
/>