diff --git a/package.json b/package.json index 5d08a32..51b84c6 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "@openreplay/tracker": "^14.0.4", "@tanstack/react-query": "^5.17.0", "aos": "^2.3.4", + "browser-image-compression": "^2.0.2", "capacitor-plugin-safe-area": "^4.0.0", "chrono-node": "^2.7.7", "dotenv": "^16.4.5", @@ -54,9 +55,12 @@ "moment": "^2.30.1", "murmurhash": "^2.0.1", "prop-types": "^15.8.1", + "quill": "^2.0.3", + "quilljs-markdown": "^1.2.0", "react": "^18.2.0", "react-calendar": "^5.1.0", "react-dom": "^18.2.0", + "react-easy-crop": "^5.4.2", "react-router-dom": "^6.21.1", "react-transition-group": "^4.4.5", "reactjs-social-login": "^2.6.3", diff --git a/src/utils/Fetcher.jsx b/src/utils/Fetcher.jsx index e2b0630..d36f132 100644 --- a/src/utils/Fetcher.jsx +++ b/src/utils/Fetcher.jsx @@ -480,6 +480,13 @@ const PutWebhookURL = url => { }) } +const GetStorageUsage = () => { + return Fetch(`/users/storage`, { + method: 'GET', + headers: HEADERS(), + }) +} + export { AcceptCircleMemberRequest, ArchiveChore, @@ -509,6 +516,7 @@ export { GetLabels, GetLongLiveTokens, GetResource, + GetStorageUsage, GetSubscriptionSession, GetThingHistory, GetThings, diff --git a/src/utils/Helpers.jsx b/src/utils/Helpers.jsx index 17c0351..aeafe6c 100644 --- a/src/utils/Helpers.jsx +++ b/src/utils/Helpers.jsx @@ -1,7 +1,18 @@ import moment from 'moment' +import { getAssetURL } from './TokenManager' const isPlusAccount = userProfile => { return userProfile?.expiration && moment(userProfile?.expiration).isAfter() } -export { isPlusAccount } +const resolvePhotoURL = url => { + if (!url) return '' + if (url.startsWith('http') || url.startsWith('https')) { + return url + } + if (url.startsWith('assets')) { + return getAssetURL(url) + } + return url +} +export { isPlusAccount, resolvePhotoURL } diff --git a/src/utils/imageCropUtils.js b/src/utils/imageCropUtils.js new file mode 100644 index 0000000..a4cd051 --- /dev/null +++ b/src/utils/imageCropUtils.js @@ -0,0 +1,45 @@ +// Utility to crop and resize an image to a square (e.g. 320x320) and return a JPEG Blob +// Usage: await getCroppedImg(imageSrc, croppedAreaPixels, width, height, mimeType) +export async function getCroppedImg( + imageSrc, + crop, + width, + height, + mimeType = 'image/jpeg', +) { + return new Promise((resolve, reject) => { + const image = new window.Image() + image.crossOrigin = 'anonymous' + image.onload = () => { + const canvas = document.createElement('canvas') + canvas.width = width + canvas.height = height + const ctx = canvas.getContext('2d') + // Draw the cropped image to the canvas + ctx.drawImage( + image, + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + width, + height, + ) + canvas.toBlob( + blob => { + if (!blob) { + reject(new Error('Canvas is empty')) + return + } + resolve(blob) + }, + mimeType, + 0.92, + ) + } + image.onerror = error => reject(error) + image.src = imageSrc + }) +} diff --git a/src/views/ChoreEdit/ChoreEdit.jsx b/src/views/ChoreEdit/ChoreEdit.jsx index c748381..c23f2f4 100644 --- a/src/views/ChoreEdit/ChoreEdit.jsx +++ b/src/views/ChoreEdit/ChoreEdit.jsx @@ -21,7 +21,6 @@ import { Snackbar, Stack, Switch, - Textarea, Typography, } from '@mui/joy' import moment from 'moment' @@ -42,11 +41,13 @@ import { import { isPlusAccount } from '../../utils/Helpers' import Priorities from '../../utils/Priorities.jsx' import LoadingComponent from '../components/Loading.jsx' +import RichTextEditor from '../components/RichTextEditor.jsx' import SubTasks from '../components/SubTask.jsx' import { useLabels } from '../Labels/LabelQueries' import ConfirmationModal from '../Modals/Inputs/ConfirmationModal' import LabelModal from '../Modals/Inputs/LabelModal' import RepeatSection from './RepeatSection' + const ASSIGN_STRATEGIES = [ 'random', 'least_assigned', @@ -391,10 +392,18 @@ const ChoreEdit = () => { Additional Details : What is this task about? -