602 Commits

Author SHA1 Message Date
Mo Tarbin
74d658f928 Release 1.2.16 2026-07-18 03:15:20 -04:00
Mohamad Tarbin
24a1572752 Merge pull request #153 from donetick/upload-and-attachment
Improve Offline mode and stop temp id position, stuck commands can no…
2026-07-18 02:32:11 -04:00
Mo Tarbin
80099635be Improve Offline mode and stop temp id position, stuck commands can no longer block the pipeline, Fix Spurious Offline flip, Ghost Chore when switching accounts 2026-07-18 02:31:00 -04:00
Mohamad Tarbin
cd28526ccc Merge pull request #152 from donetick/upload-and-attachment
Upload and attachment
2026-07-18 02:28:12 -04:00
Mo Tarbin
277e10daf1 fix IOS sqlite return metadata as first row 2026-07-18 02:20:31 -04:00
Mo Tarbin
a6fb3c87c4 Refactor Attchemnt Upload and fix bug with signing 2026-07-18 02:16:42 -04:00
Mohamad Tarbin
bf6474a488 Merge pull request #151 from donetick/deeplink-fixes
Fix Notification deeplink
2026-07-17 19:34:01 -04:00
Mo Tarbin
08f8d6ac6a Fix Notification deeplink 2026-07-17 19:33:33 -04:00
Mo Tarbin
0c80efc686 add mapping for crowdin 2026-07-16 22:35:45 -04:00
Mo Tarbin
e1b6561b70 %two_letters_code% to %locale% in crowdin.yml. 2026-07-16 22:24:46 -04:00
Mo Tarbin
56e91db0b4 Release 1.2.12 : Remove NDEF and PACE from NFC permission. fix login with google entitlement 2026-07-16 20:55:40 -04:00
Mohamad Tarbin
ce3b6fdc37 Merge pull request #149 from donetick/fix-login-with-google-2
fix(ios): register Google Sign-In URL scheme to prevent launch crash
2026-07-16 19:41:03 -04:00
Mo Tarbin
885427fa85 fix(ios): register Google Sign-In URL scheme to prevent launch crash
Merge duplicate CFBundleURLTypes entries in Info.plist so the Google
reversed-client-ID scheme and the donetick deep-link scheme coexist.
The second entry was overriding the first, causing GIDSignIn to throw
NSInvalidArgumentException for a missing URL scheme.
2026-07-16 19:40:34 -04:00
Mo Tarbin
b77365e60f Release 1.2.12 2026-07-16 19:07:50 -04:00
Mohamad Tarbin
b3d601aa35 Merge pull request #148 from donetick/fix-login-with-google
Fix login with google
2026-07-16 18:53:57 -04:00
Mo Tarbin
f1aca45ce3 Update version 2026-07-16 18:53:32 -04:00
Mo Tarbin
46b1902af2 force login before login with google 2026-07-16 18:52:05 -04:00
Mohamad Tarbin
96cee7e5c2 Merge pull request #140 from donetick/07-14-bug-fixes
07 14 bug fixes
2026-07-14 21:10:11 -04:00
Mo Tarbin
8a32811226 Add Advance option section 2026-07-14 19:15:20 -04:00
Mohamad Tarbin
18dbaee4b5 Merge pull request #139 from donetick/fastline
Integrate with Fastline to automate App stores/ Playstore release
2026-07-14 17:34:28 -04:00
Mo Tarbin
9c7cea23a7 Add More options to AddTaskModal to handle most of the things we have in editChore 2026-07-14 14:24:43 -04:00
Mo Tarbin
519b085dd2 fix: pressing shift +enter in task title field open the task desc 2026-07-14 14:22:34 -04:00
Mo Tarbin
66d3bc6c7b fix: add ability to create label in label picker 2026-07-14 12:59:47 -04:00
Mo Tarbin
40270f219a Fix: make sure the calendar doesn't take the full screen on desktop 2026-07-14 12:29:32 -04:00
Mo Tarbin
08fba15fee fix https://github.com/donetick/frontend/issues/95 2026-07-14 12:24:40 -04:00
Mo Tarbin
379e1a354b Update to include publishing the apps 2026-07-14 12:17:13 -04:00
Mo Tarbin
eacfca715c Integrate with Fastline, Create a release script 2026-07-14 12:16:36 -04:00
Mo Tarbin
4bfff4b7e9 Add script to handle secrets fetching 2026-07-14 11:57:29 -04:00
Mo Tarbin
bbad583e53 fix: correct day-of-month recurrence parsing to use monthly interval and set next due date 2026-07-14 11:15:50 -04:00
Mo Tarbin
359202a594 fix: clear offline data on logout, session expiry, server change, and login
Offline DB was never wiped during logout, token expiry, or server URL
change, allowing stale data to persist across users and servers. Also
plugs the refresh-token expiry path which bypassed handleLogout entirely.
2026-07-14 11:08:46 -04:00
Mo Tarbin
7f68f7dd9d update permissions in AndroidManifest.xml for better compatibility and security to fix google play issue:
```Your app cannot make use of the READ_MEDIA_IMAGES or READ_MEDIA_VIDEO permissions because it only needs one-time or infrequent access to a device’s media files. To use these permissions, your app’s core functionality must need persistent access to photo and video files.
```
2026-07-13 02:44:14 -04:00
Mo Tarbin
77a9de570c release Prep: update version codes to 28 and marketing version to 1.2.7 in build.gradle, project.pbxproj, and package.json 2026-07-13 00:50:03 -04:00
Mo Tarbin
a02b193b90 implement NFC intent normalization in MainActivity for Donetick 2026-07-13 00:46:48 -04:00
Mo Tarbin
789eb30d2b chore: update iOS project version to 28 and marketing version to 1.2.6; add sensitive files to .gitignore 2026-07-13 00:32:04 -04:00
Mohamad Tarbin
7a653a5bb7 Merge pull request #135 from donetick/bugfixes-07-09-2026
improve task management
2026-07-13 00:21:40 -04:00
Mo Tarbin
c929977773 add filter options for created and updated dates in SortAndGrouping component 2026-07-13 00:17:27 -04:00
Mo Tarbin
d21ec9d727 make choosing color match advance filter color selector 2026-07-12 23:34:47 -04:00
Mo Tarbin
5332d0ac62 streamline task management in SubTask component. have better shortcut and keyboard movement 2026-07-12 23:34:19 -04:00
Mo Tarbin
6508eb57fc Merge branch 'develop' of https://github.com/Donetick/frontend into bugfixes-07-09-2026 2026-07-12 18:11:22 -04:00
Mo Tarbin
b7cc19b719 format 2026-07-12 18:11:00 -04:00
Mo Tarbin
925ebf3210 fix: correct file patterns in Crowdin configuration for locale files 2026-07-12 18:07:22 -04:00
Mo Tarbin
b1ff6805eb fix: update NFC URL generation to support iOS platform in ChoreModals component 2026-07-12 18:07:22 -04:00
cm-moment
1f4646dbdc feat: 新增简体中文(zh-CN)语言汉化包
1. 新增 zh-CN 简体中文国际化目录
2. 完成 chores、common、settings 页面全部文本汉化
3. 语言编码遵循 BCP47 标准,与现有多语言目录结构统一
2026-07-12 18:07:22 -04:00
Mo Tarbin
6612e77579 fix: implement UUID generation utility and replace crypto.randomUUID usage (to support genertaion when we are in http )in task and chore components 2026-07-12 18:07:22 -04:00
tanomitsu
2fd6d5cd2e feat: add Japanese (ja) localization
- Add ja translations for common, settings, and chores namespaces
- Register ja in AVAILABLE_LANGUAGES so it appears in the language picker
- Import moment/locale/ja so date and relative-time formatting uses Japanese
2026-07-12 18:07:17 -04:00
Mohamad Tarbin
0531b97e19 Merge pull request #134 from donetick/bugfixes-07-09-2026
Update NFC URL generation for iOS and fix Crowdin file patterns
2026-07-10 01:45:58 -04:00
Mo Tarbin
7336b52e14 fix: correct file patterns in Crowdin configuration for locale files 2026-07-10 01:45:16 -04:00
Mohamad Tarbin
cc03275ad3 Merge pull request #132 from cm-moment/develop
feat: Add Simplified Chinese (zh-CN) localization新增简体中文(zh-CN)语言汉化包
2026-07-10 01:24:56 -04:00
Mo Tarbin
09909514d5 fix: update NFC URL generation to support iOS platform in ChoreModals component 2026-07-10 01:07:55 -04:00
Mohamad Tarbin
a3dd8cb00d Merge pull request #133 from donetick/bugfixes-07-09-2026
fix: implement UUID generation utility and replace crypto.randomUUID …
2026-07-09 14:44:35 -04:00
Mo Tarbin
d207f7e2b2 fix: implement UUID generation utility and replace crypto.randomUUID usage (to support genertaion when we are in http )in task and chore components 2026-07-09 14:44:05 -04:00
Mohamad Tarbin
cc348e5d35 Merge pull request #112 from tanomitsu/feature/ja-localization
Add Japanese (ja) localization
2026-07-09 11:00:19 -04:00
cm-moment
aeed19532f feat: 新增简体中文(zh-CN)语言汉化包
1. 新增 zh-CN 简体中文国际化目录
2. 完成 chores、common、settings 页面全部文本汉化
3. 语言编码遵循 BCP47 标准,与现有多语言目录结构统一
2026-07-09 20:17:36 +08:00
Mohamad Tarbin
b52f870e29 Merge pull request #131 from donetick/bugfixes-07-08-2026
Bugfixes 07 08 2026
2026-07-08 14:13:30 -04:00
Mo Tarbin
7889c32be0 fix: simplify Node.js setup in build workflow by removing version matrix 2026-07-08 14:13:18 -04:00
Mo Tarbin
1ca91d684f fix: remove redundant lint job from build workflow and ensure main branch is specified for push events 2026-07-08 14:08:41 -04:00
Mo Tarbin
648f76bd22 fix: update version codes and add local networking support in iOS Info.plist 2026-07-08 14:06:03 -04:00
Mo Tarbin
f8d772149b fix: enhance SSE connection handling for native platforms and implement ticket fetching 2026-07-08 13:56:10 -04:00
Mo Tarbin
181156de10 fix: prevent infinite reload loop in OAuth deep link handling and clean up comments in LoginView 2026-07-08 12:46:42 -04:00
Mohamad Tarbin
a038a3366f Merge pull request #130 from donetick/add-task-photo-fix
fix: update version codes and enhance document scanning functionality
2026-07-07 23:17:17 -04:00
Mohamad Tarbin
c43dc175d0 Merge branch 'develop' into feature/ja-localization 2026-07-07 23:01:46 -04:00
Mo Tarbin
fd3f7f4a37 fix: update version codes and enhance document scanning functionality 2026-07-07 21:16:30 -04:00
Mohamad Tarbin
20e5c0e292 Merge pull request #129 from donetick/fix-dependencies
chore: update iOS deployment target to 15.0 and upgrade dependencies
2026-07-07 11:22:19 -04:00
Mo Tarbin
768c639d2b chore: update iOS deployment target to 15.0 and upgrade dependencies 2026-07-07 11:21:58 -04:00
Mohamad Tarbin
9bd7f8347b Merge pull request #128 from donetick/ux-improvment-07-01-2026
Ux improvment 07 01 2026
2026-07-07 00:48:14 -04:00
Mohamad Tarbin
ae57022102 Merge pull request #127 from donetick/add-photo-ai
Add Support for OCR and attachment on tasks, redesign AddTaskModal
2026-07-07 00:25:35 -04:00
Mo Tarbin
12d95dd4b1 Fixes and remove logs 2026-07-07 00:23:36 -04:00
Mo Tarbin
57ac5cb9bf feat: enhance user profile photo handling with URL resolution and profile refresh 2026-07-06 18:12:23 -04:00
Mo Tarbin
24508be4d4 feat: implement attachment browser and viewer modals, enhance chore attachment handling 2026-07-06 18:11:57 -04:00
Mo Tarbin
9136ff3ea3 feat: enhance file upload and attachment management with draft support 2026-07-06 18:10:43 -04:00
Mo Tarbin
4460d80b72 Ability to have open OCR from the field 2026-07-04 15:22:24 -04:00
Mo Tarbin
eb8c178603 Add ability to move project from choreactionMenu
fix header not syncing on mychoreHeader
2026-07-04 12:00:12 -04:00
Mohamad Tarbin
ad08cfaad0 Merge pull request #126 from donetick/advance-filtering
Advance filtering
2026-07-04 02:25:31 -04:00
Mo Tarbin
96845ad7cf fix merge issue 2026-07-04 02:19:47 -04:00
Mohamad Tarbin
16412821bf Merge branch 'develop' into advance-filtering 2026-07-04 02:06:18 -04:00
Mo Tarbin
3c0f4402a8 add dependencies 2026-07-03 23:31:43 -04:00
Mo Tarbin
260087d1fa Add Ability to turnOCR photo then create task (Merge support-local-ai) 2026-07-03 23:31:19 -04:00
Mo Tarbin
3361ef949a Ability to open edit entry from HistoryDetailsModal 2026-07-03 15:45:15 -04:00
Mo Tarbin
dfe0e960dc Ability to open the modal for more details in actitityView 2026-07-03 14:56:44 -04:00
Mo Tarbin
98e0623cb7 Make sure the Activity view match with History Icons 2026-07-03 14:56:12 -04:00
Mo Tarbin
97084db4de Add HistoryDetailModal component for detailed activity view 2026-07-03 14:25:12 -04:00
Mo Tarbin
165c76bb69 feat: Implement advanced filtering in FilterBar and integrate ActiveFilterChips component
- Refactored FilterBar to utilize ActiveFilterChips for displaying active filters.
- Added selectable chip styles and improved hover effects for better UX.
- Enhanced filter handling with new props for managing active filters and results count.
- Introduced new hooks and state management for custom filters in MyChores and UserActivities.
- Updated ChoreToolbar to support new filter functionalities and improved UI components.
- Added client-side filtering capabilities in UserActivities with dynamic filter definitions.
2026-07-03 14:24:05 -04:00
Mo Tarbin
e0e4145481 Due date grouping show as timeline ( break by date not like smart groups) 2026-07-03 11:51:18 -04:00
Mo Tarbin
8c4e7e0e43 Center the text in the Quick filter chips 2026-07-03 11:49:27 -04:00
Mohamad Tarbin
dee41dad9e Merge pull request #125 from donetick/add-task-modal-v2
Add task modal v2
2026-07-03 02:01:33 -04:00
Mo Tarbin
47d596af08 feat: enhance DueDatePickerField with quick date and time selection options 2026-07-03 01:58:31 -04:00
Mo Tarbin
4019a7c225 feat: update AddTaskModal and SmartTaskTitleInput components for improved functionality and styling 2026-07-03 01:58:08 -04:00
Mo Tarbin
db0c199674 feat: refactor NotificationTemplate and remove unused components for cleaner code 2026-07-02 20:53:12 -04:00
Mo Tarbin
f11a1fd9cc feat: add DueDatePickerPreview component for managing due dates and times
feat: implement LabelsPickerField component for selecting multiple labels

feat: create NotificationPickerField component for managing notification reminders

feat: add PriorityPickerField component for selecting task priority levels

feat: implement ProjectPickerField component for selecting projects

feat: create RepeatPickerField component for setting up recurring tasks

feat: add RepeatPickerPreview component for displaying and selecting repeat options
2026-07-02 20:51:53 -04:00
Mo Tarbin
892754bbae feat: enhance error handling UI with detailed messages and copy functionality 2026-07-01 22:43:58 -04:00
Mohamad Tarbin
a0de0c2005 Merge pull request #111 from donetick/issue-108
Add MFA handling to AuthenticationLoading component
2026-06-30 01:52:57 -04:00
Mo Tarbin
6b5f5c54dd Add MFA handling to AuthenticationLoading component 2026-06-30 01:45:12 -04:00
Mohamad Tarbin
fdac632b1c Merge pull request #124 from donetick/bug-fixes-06-27-2026
Bug fixes 06 27 2026
2026-06-30 01:23:52 -04:00
Mo Tarbin
43f804c7a8 Fix: Export polling constants and synchronize retry intervals in SyncStatusIndicator 2026-06-30 01:21:17 -04:00
Mo Tarbin
e85220d727 Fix: Changing URL for backend requiring restart.
Fix: Add better feedback so user know if the url invalid or unreachable
2026-06-30 01:17:52 -04:00
Mo Tarbin
489d46e922 Fix : Display better login errors 2026-06-27 22:24:15 -04:00
Mo Tarbin
b2fdb049e2 Fix: update chore state handling on delete and archive actions
Response from backend just say sucessfull so we need to use the chore optimisitcally
2026-06-27 22:22:57 -04:00
Mo Tarbin
878031cae8 Fix: Make sure notification skip for achieve tasks
https://github.com/donetick/donetick/issues/695
2026-06-27 22:19:12 -04:00
Mohamad Tarbin
aeb0b90281 Merge pull request #116 from scottanderson/fix-assignee
fix: Set assignee bug
2026-06-23 00:19:25 -04:00
Mohamad Tarbin
83eb04eed3 Merge pull request #119 from scottanderson/anyone
Improve `anyone` UX
2026-06-22 23:27:03 -04:00
Scott Anderson
aeb3916741 Set anyone when everyone is deselected 2026-06-18 12:55:53 -04:00
Mohamad Tarbin
c42b0677d1 Merge pull request #104 from nicholasremm/feature/fix-oauth2-refresh-token
fix(mobile): Store refresh token when using OAuth2 provider
2026-06-17 20:32:49 -04:00
Scott Anderson
08f7e4900c Improve anyone UX 2026-06-17 04:45:00 -04:00
Mo Tarbin
8e5c31f7f3 remove the old filter logic and use advance filter in myChore 2026-06-14 15:55:19 -04:00
Mo Tarbin
23e777cd94 implement unified ChoreToolbar and enhance ChoreHistory with filtering options 2026-06-14 15:54:40 -04:00
Mo Tarbin
fe22bb1035 feat: enhance AdvancedFilterBuilder with new filtering options and UI improvements
- Introduced new filter options for due dates, points, and chore statuses.
- Refactored condition management to use selections for better state handling.
- Improved UI components for filter conditions, including chips for selection.
- Added a bottom sheet modal for filter creation and editing.
- Enhanced user experience with clear actions and previews for selected filters.
2026-06-12 21:31:17 -04:00
Mohamad Tarbin
0da9c7f965 Merge pull request #118 from donetick/capacitor-nfc-tag-scanner
add NFC capabilities for native apps
2026-06-07 16:36:24 -04:00
Mo Tarbin
48adb0b256 feat: update app version to 1.2.3, add NFC capabilities, and enhance deep link handling 2026-06-07 16:32:43 -04:00
Scott Anderson
b2eeeeddfb cleanup 2026-06-06 20:17:04 -04:00
Mohamad Tarbin
5ee2b6de48 Merge pull request #117 from donetick/offline-support-v2.3
Offline support v2.3
2026-06-06 14:14:05 -04:00
Mo Tarbin
4e0b5d79df feat: enhance offline support with improved network management and sync handling 2026-06-06 00:58:18 -04:00
Scott Anderson
027fac90b4 fix: Set assignee bug 2026-06-04 01:45:38 -04:00
Mo Tarbin
24118e0dc3 Chore create and update doesn't return useful other than id when we area creating. so we dismiss the value being returned 2026-05-31 19:04:04 -04:00
Mohamad Tarbin
faf478a092 Merge pull request #114 from donetick/develop-rebased
Rebase Main with Develop
2026-05-30 22:10:55 -04:00
Mo Tarbin
f4a7b00b1b refactor: remove unused script tag for analytics from index.html 2026-05-30 22:10:23 -04:00
Mohamad Tarbin
df7680e06c Merge branch 'develop' into develop-rebased 2026-05-30 22:09:50 -04:00
Mo Tarbin
bbe68974b2 Refactor date parsing logic to validate word boundaries, preventing partial matches for days and months 2026-05-30 22:04:51 -04:00
Mo Tarbin
aad300bd9c Enhance due date parsing by validating word boundaries to prevent partial matches 2026-05-30 22:04:51 -04:00
Mo Tarbin
12ce568d3c refactor: update offline support notifications and confirmation messages for clarity 2026-05-30 22:04:51 -04:00
Mo Tarbin
25d3f76f9e feat: implement offline support for chore archiving and unarchiving, enhance state management for pending commands 2026-05-30 22:04:51 -04:00
Mo Tarbin
aece93d63d including improved command handling and sync status updates 2026-05-30 22:04:51 -04:00
Mo Tarbin
45e667abf7 add network listener management and enhance sync on reconnect functionality 2026-05-30 22:04:51 -04:00
Mo Tarbin
5869b39035 feat: enhance chore management with history and sync improvements
- Added support for starting and pausing chores with offline handling.
- Implemented chore history updates and deletions with pending command management.
- Enhanced sync engine to handle chore history changes and deletions.
- Introduced a PendingBadge component to display pending actions for chore history.
- Updated DeveloperSettings to include sync diagnostics and reset functionality.
- Improved user notifications for offline actions and pending commands.
- Refactored ChoreView to dynamically generate info cards based on chore history.
- Added sync status indicator with cancel all functionality for pending commands.
2026-05-30 22:04:51 -04:00
Mo Tarbin
d981d57a8f feat: implement offline support for labels and projects, enhance advanced settings with offline feature toggle, and add sync status indicator
- Added offline support for fetching and caching labels and projects using `offlineDB`.
- Enhanced `AdvancedSettings` to include an offline feature toggle with confirmation modal for disabling offline support.
- Introduced `SyncStatusIndicator` component to display sync status, pending commands, and failed commands.
- Created `PendingBadge` component to manage and display pending actions for synchronization.
- Removed deprecated offline mode toggle from `StorageSettings`.
- Improved error handling and user notifications for offline actions and sync processes.
2026-05-30 22:04:45 -04:00
Mo Tarbin
1f9d1edc5c Add status handling for 'Missed' and 'Rescheduled' activities in ActivityItem 2026-05-30 22:04:25 -04:00
Mohamad Tarbin
4944ee6078 Merge pull request #113 from donetick/donetick.com-clean
Rebase to Donetick.com branch
2026-05-30 21:55:57 -04:00
Mo Tarbin
c4b2b909e0 Squashed commit of the following:
Rebase from Donetick.com branch
commit 2a73d3240cab4b1624cc92e97cbf88d28ea97339
Merge: e6f7aa9 c6865f4
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Apr 14 13:16:01 2026 -0400

    Merge branch 'main' into donetick.com

commit e6f7aa98d1afdd63bca7172b647443edab72e0ec
Merge: f502dc4 4713e99
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Apr 7 00:43:25 2026 -0400

    Merge branch 'main' into donetick.com

commit f502dc4e76d6215a2ea4421ba9d4efd690087d14
Merge: 92ff8a5 1e122b3
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Apr 7 00:41:20 2026 -0400

    Merge branch 'main' into donetick.com

commit 92ff8a532c399b89e1bc9a747f7ee261bc2a3a75
Merge: 0297738 c87335f
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Apr 7 00:05:24 2026 -0400

    Merge branch 'main' into donetick.com

commit 0297738c0648cc740cc6c5ece0744ac83a9309f6
Merge: e7df60c 12cba1f
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Apr 5 23:41:46 2026 -0400

    Merge branch 'main' into donetick.com

commit e7df60c504594bb0079637ff5aef9c6fb24e30b4
Merge: 0a4c5ed 0b19cdc
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Mar 23 22:32:08 2026 -0400

    Merge branch 'main' into donetick.com

commit 0a4c5ed3870c20ed13c45e9caffd29d55aafcd5d
Merge: 4805cbb f483653
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Feb 16 18:30:25 2026 -0500

    Merge branch 'main' into donetick.com

commit 4805cbb8f7117f184aaaa35ae549a3433baee3d7
Merge: 96649ed 0b7d7bb
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Feb 14 17:01:26 2026 -0500

    Merge branch 'main' into donetick.com

commit 96649ed012028c8d55feb130f4c67f299522f5dc
Merge: a89f9b9 d8d7b6a
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Feb 10 23:22:08 2026 -0500

    Merge branch 'main' into donetick.com

commit a89f9b9525568775dba16464c61bce5ffe1c858b
Merge: 3550d23 1786a5e
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Feb 10 20:40:06 2026 -0500

    Merge branch 'main' into donetick.com

commit 3550d23639b0e8eea9e8449b1452a6e08617fb75
Merge: 160bd81 430e602
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Feb 10 11:46:30 2026 -0500

    Merge branch 'main' into donetick.com

commit 160bd814bea4fea2c8c2ae9469ecddb8bbdefbc3
Merge: 68df100 4525aee
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Feb 10 11:12:31 2026 -0500

    Merge branch 'main' into donetick.com

commit 68df100b63db2f8ce8169699cf8c757bc7c5fa86
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Feb 10 11:08:58 2026 -0500

    chore: update version to 0.3.0 and add version bump scripts

    - Bumped version from 0.1.145 to 0.3.0 in package.json
    - Added npm scripts for version bumping: bump, bump:minor, and bump:major
    - Added capacitor-set-version dependency

commit 39fb8aeebc330bf22ab6015e119900dabe353238
Merge: 070abf9 a9cff1f
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Feb 10 01:24:01 2026 -0500

    Merge branch 'main' into donetick.com

commit 070abf9c81a6b450efe090811bf56d166087edf7
Merge: 2a11069 ef232ab
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Feb 9 23:31:36 2026 -0500

    Merge branch 'main' into donetick.com

commit 2a11069831cc780e82450a8ebdb6dc8b9e0aa7b9
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Feb 8 23:01:49 2026 -0500

    update API keys in configuration files for security and compliance

commit 216befc69ef9d13bba4ab2ddb8ce189f513109f8
Merge: 23f1d7e 7663a53
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Feb 8 21:56:44 2026 -0500

    Merge branch 'main' into donetick.com

commit 23f1d7efe4fc38f7c3428dc8fc740e3b56c6d485
Merge: d5ab457 bec69b4
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Feb 8 16:34:02 2026 -0500

    Merge branch 'main' into donetick.com

commit d5ab45789e946c16b89a95858c7173e96ed87316
Merge: fde04f2 666eb75
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Feb 8 16:20:44 2026 -0500

    Merge branch 'main' into donetick.com

commit fde04f268052d765be65e78df7ba7937f99a1c8c
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Feb 8 11:17:01 2026 -0500

    fix: update version codes and names in output-metadata.json and Podfile.lock

commit 1aa592ccb2c3b79ae5751c09566280b5fedb50f7
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Feb 8 11:10:27 2026 -0500

    fix: add missing newline at end of package.json

commit f9df5b27240ab6e038a11d25ff6d6adb39e2bb0b
Merge: 501f1a5 00e6cf5
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Feb 8 10:30:07 2026 -0500

    Merge branch 'main' into donetick.com

commit 501f1a5ca3d405e34010a7e825e342bb1e7a1665
Merge: bed45a1 753d4cd
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Feb 8 10:28:05 2026 -0500

    Merge branch 'main' into donetick.com

commit bed45a13a1a9780ac6ad9c64297730e1b7f22534
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Dec 29 15:34:20 2025 -0500

    chore: update Gradle distribution URL to version 8.12

commit a7a91fd1ebd0100f99770e1d8c5e5ebc4864c7e9
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Dec 29 15:33:51 2025 -0500

    feat: update RevenueCat API key handling for iOS and Android in AccountSettings and Settings components

commit a2142b36365c0fc8d094adbde10746cd2a7ac6a0
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Dec 1 17:52:40 2025 -0500

    bump version code and name to 1.0.20 for Android and iOS

commit 215bb7d5c91afc2746275e85894b63515f2cdfd3
Merge: f0cb7d6 7cb2f20
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Dec 2 00:23:50 2025 -0500

    Merge branch 'main' into donetick.com

commit f0cb7d62ad7736bd3d49d0f4ff74ca147bf9d789
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Fri Oct 3 00:56:48 2025 -0400

    chore: update version codes and dependencies for Android and iOS

commit 0ed061e7ad63fd406c5f4051e19dfaff719cb8e9
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Fri Oct 3 00:56:00 2025 -0400

    feat: add PRODUCT_BUNDLE_IDENTIFIER to project configuration

commit 9987813265bc808e37e0298e4463d52a71d7cfec
Merge: 0257074 04314d5
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Fri Oct 3 00:44:16 2025 -0400

    Merge branch 'main' into donetick.com

commit 02570740ab1cd404bfc3c9d19539a7f67f94a317
Merge: 719708c 68f0912
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Sep 28 19:33:12 2025 -0400

    Merge branch 'main' into donetick.com

commit 719708cd185da9791411299632ab940c7ca0b15a
Merge: 4ffaa75 ac2d491
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Sep 28 19:31:22 2025 -0400

    Merge branch 'main' into donetick.com

commit 4ffaa75aea9b2a0f91e92594fbdef87763afd15e
Merge: 7e1deae 7658b4c
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Sep 28 02:46:53 2025 -0400

    Merge branch 'main' into donetick.com

commit 7e1deae9cf9c96253526fa03ee0bce42ca1e3f9d
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Sep 27 13:35:06 2025 -0400

    chore: update project version to 1.0.18 and increment current project version to 18

commit ad041aeee88076793e23ce5da11f8e945d16e5d6
Merge: bb6a05a d28ecb5
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Fri Sep 26 02:22:01 2025 -0400

    Merge branch 'main' into donetick.com

commit bb6a05a6b4c291333dc365824634ebbb92b57e6e
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Wed Sep 24 02:05:05 2025 -0400

    chore: update version codes and marketing version to 1.0.6 for Android and iOS builds

commit fac7225da9e509edb8735c3ec1e27e7861c9befd
Merge: 4aa17a0 fd6e488
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Sep 21 13:06:56 2025 -0400

    Merge branch 'main' into donetick.com

commit 4aa17a0addfa6bd2b7d3012810d969cfda075ce2
Merge: bf4abea 79dfb11
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Sep 20 22:22:31 2025 -0400

    Merge branch 'main' into donetick.com

commit bf4abea73bc2f9cce732d6b2cd4b5fc8a59369e1
Merge: 7ed2a50 3bf9126
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Sep 20 19:08:51 2025 -0400

    Merge branch 'main' into donetick.com

commit 7ed2a50a6926249355a885d5f2c0d7339b15f3b1
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Sep 18 01:09:50 2025 -0400

    Update google-service with fcm details. add support for push notification and push new version for the

commit 79017f91c6472656891ed5918fc12cad6182817f
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Sep 15 23:58:13 2025 -0400

    refactor: remove unnecessary import statement in PrivacyPolicyView component

commit e40ea550f14a93d4fb275af8390f30a02ff3a52f
Merge: cba69af b71a533
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Sep 15 23:58:00 2025 -0400

    Merge branch 'main' into donetick.com

commit cba69af2856596c8e255211074094d96b0194e06
Merge: bf4e6aa 36093b9
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Sep 14 22:06:14 2025 -0400

    Merge branch 'main' into donetick.com

commit bf4e6aa3c90d6fca08d5ca6f3891b24fe68e73fb
Merge: ab0f603 bd14a35
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Sep 14 21:59:46 2025 -0400

    Merge branch 'main' into donetick.com

commit ab0f60320b5ed3673a56f8c5fbb4bd32c722f08e
Merge: 165bc07 219aa06
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Sep 11 01:20:23 2025 -0400

    Merge branch 'main' into donetick.com

commit 165bc074a38239d4d2d5dc4326ced7794fbfc178
Merge: 70a8d3c b152da9
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Sep 4 09:17:56 2025 -0400

    Merge branch 'main' into donetick.com

commit 70a8d3cfd77ee1d9de66a373892486be1bc0510d
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Sep 4 03:09:28 2025 -0400

    fix: updated tablet installation section

commit ed1a35aa364f81c9f2aae14b3b342b5e1c2797e8
Merge: baabd4e 14ce230
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Sep 4 03:01:58 2025 -0400

    Merge branch 'main' into donetick.com

commit baabd4e5b26cb2d849cc73c0ca12597d46f8b526
Merge: 3935b26 a65cb92
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Sep 4 03:00:08 2025 -0400

    Merge branch 'main' into donetick.com

commit 3935b265cf78edcda2126eb133313482e087f2f4
Merge: b06cef2 4a54115
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Sep 4 02:52:37 2025 -0400

    Merge branch 'main' into donetick.com

commit b06cef2c2b982f195c4d55485ec4b013361b8037
Merge: be0f64d 057c5f7
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Sep 4 01:49:49 2025 -0400

    Merge branch 'dev' into donetick.com
    ::# the commit.

commit be0f64d11ecb190e6999e03222f7f5d8d37d55e7
Merge: 480ee88 fd15235
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Sep 2 17:39:34 2025 -0400

    Merge branch 'main' into donetick.com

commit 480ee8818ad6406194b1c224445652f19dbf7cae
Merge: a225768 4e31190
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Aug 30 01:36:52 2025 -0400

    Merge branch 'main' into donetick.com

commit a225768e98639339df81b05699df50abde7d6e25
Merge: c251ee9 e99a066
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Fri Aug 29 00:56:56 2025 -0400

    Merge branch 'main' into donetick.com

commit c251ee99a4e7c5852d5a798dd7fa473bce96da9f
Merge: be02a6d 6b5a874
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Aug 26 22:11:46 2025 -0400

    Merge branch 'main' into donetick.com

commit be02a6dca0958cec8bdfc408497dd999429caaf0
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Aug 26 17:53:43 2025 -0400

    Refactor ChoreCard: remove unused circle members data and update approval logic

commit d1e93c24e3bb917a2d26ad43ddc21a88cb9426e9
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Aug 26 17:43:07 2025 -0400

    Add chore filtering by selected date and update navigation for localhost

commit d38e0c4ac7bdd790541a15eee471ad42afd01b34
Merge: 9098f9e defc7a8
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Aug 25 23:59:06 2025 -0400

    Merge branch 'main' into donetick.com

commit 9098f9e0304022fcbbb61f88cd79a5cf02489e0f
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Aug 25 23:54:04 2025 -0400

    Remove unnecessary dependencies and clean up wrangler configuration

commit c51cc3a73c568200ee8905cb340ad85e201b7956
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Aug 25 23:51:04 2025 -0400

    Add wrangler configuration for Cloudflare Workers deployment

commit e7ec5f2b05312bdfe5297aefd3c19cf52b20f932
Merge: 2bfe42f 06d568e
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Aug 25 23:42:23 2025 -0400

    Merge branch 'main' into donetick.com

commit 2bfe42f6f1729fc304a73a08d46a0b0969b1baaf
Merge: 6429fb8 6064c88
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Aug 25 23:40:58 2025 -0400

    Merge branch 'main' into donetick.com

commit 6429fb8aca1b2bfc9cb36c86d888c31e37182efd
Merge: 918a5fa 77b3430
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Aug 24 12:25:12 2025 -0400

    Merge branch 'main' into donetick.com

commit 918a5fa7e89ecb310c3f50352bbc900a383be8a2
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Aug 2 18:53:18 2025 -0400

    add RevenueCat API key to production environment variables

commit ef8d17cec88a5a3c7ba7ecdc0a793c104fc1fe55
Merge: 267de24 18743f6
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Jul 29 00:12:33 2025 -0400

    Merge branch 'main' into donetick.com

commit 267de24b125e8754a0cab8997d10b9602886a27c
Merge: eefe3bb 63d1b86
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jul 20 10:41:56 2025 -0400

    Merge branch 'main' into donetick.com

commit eefe3bbbe99cdfb28eb335bec8a4afd763544068
Merge: a4c1187 1efab98
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Jul 19 01:18:43 2025 -0400

    Merge branch 'main' into donetick.com

commit a4c1187c34a9cfbf944e05eab2af80a48642a230
Merge: ce3a97e e6400d8
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Jul 19 00:56:06 2025 -0400

    Merge branch 'main' into donetick.com

commit ce3a97e8f43aad43ce3ee3d5664dc7f03ba6f69e
Merge: a3c4f1a 9d9c12a
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Jul 15 07:58:29 2025 -0400

    Merge branch 'main' into donetick.com

commit a3c4f1a6149fd84381cfd916e4f5ce2b59d63a30
Merge: b062f2f 0b57e42
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Jul 14 02:06:27 2025 -0400

    Merge branch 'main' into donetick.com

commit b062f2f9152420a0d2c84ede1b49fd5f52ada432
Merge: fde32a4 8d9a3cb
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jul 13 01:33:50 2025 -0400

    Merge branch 'main' into donetick.com

commit fde32a4db4183019e9b4057f0c7bb983e61c644b
Merge: 011ed3c 9f2d0b5
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jul 13 01:31:04 2025 -0400

    Merge branch 'main' into donetick.com

commit 011ed3c89a5d5760d9d3bc22e963a140fd91397c
Merge: f6d4507 f6085aa
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jul 13 00:53:11 2025 -0400

    Merge branch 'main' into donetick.com

commit f6d45072b2894b967ac8b301f4d2c56297080f19
Merge: 76946d3 8a240d5
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jul 13 00:37:26 2025 -0400

    Merge branch 'main' into donetick.com

commit 76946d39daaf3e18805d745b1da0c4f478616c7e
Merge: 1ef7c49 c8d13a6
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Jul 12 16:37:20 2025 -0400

    Merge branch 'main' into donetick.com

commit 1ef7c498cfa4a714ebe6baf07a85568a6832bc0c
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Jul 12 02:44:05 2025 -0400

    remove unnecessary whitespace and improve comments in StatusBarManager

commit 70e7864884c7aee3004c4b8b19518203bd4dcba5
Merge: dfc2ff5 b6fea7d
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Jul 12 02:43:26 2025 -0400

    Merge branch 'main' into donetick.com

commit dfc2ff5993e1471d99960dee6315b4838a952018
Merge: ff4ccfc 807dc61
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Jul 12 02:20:06 2025 -0400

    Merge branch 'main' into donetick.com

commit ff4ccfcbb64307f2668155b2e327cd5b98bf7a3c
Merge: 7eace25 4576ddf
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Jul 12 00:45:41 2025 -0400

    Merge branch 'main' into donetick.com

commit 7eace25ae9779becf349c490e88caa4a5fc84c6e
Merge: 8de5a78 3bab677
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Jun 23 01:55:47 2025 -0400

    Merge branch 'main' into donetick.com

commit 8de5a787b31cbad2e09a7470f63a46d72f13bd03
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Jun 23 01:46:44 2025 -0400

    fix: update Capacitor and CapgoCapacitorSocialLogin versions in Podfile.lock

commit 81480982210d213379c093efbc3523ce77fef5d6
Merge: c0d1071 ea70aa2
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Jun 23 01:17:20 2025 -0400

    Merge branch 'main' into donetick.com

commit c0d1071cf9bd999e428d2786031ecbb0164668e7
Merge: 836d93a fe5a72a
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Jun 21 01:20:09 2025 -0400

    Merge branch 'main' into donetick.com

commit 836d93af08af34027098221df59ae906b17256aa
Merge: 8e97ee2 eaaeee6
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Jun 21 01:01:09 2025 -0400

    Merge branch 'main' into donetick.com

commit 8e97ee2f516508a6910abca588ad514dd36a91a9
Merge: decf250 78b156d
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jun 8 10:52:46 2025 -0400

    Merge branch 'donetick.com' of https://github.com/meauxt/donetick-frontend into donetick.com

commit 78b156d76e2cc739456fbe04b0debfc1d51042c5
Author: Mohamad Tarbin <mhed.t91@gmail.com>
Date:   Tue Jun 3 23:47:33 2025 -0400

    Dev (#5)

    * refactor: Update chore grouping and color constants for improved clarity and organization

    * refactor: Update due date display logic and fix performer ID reference in ChoreCard component

    * refactor: Rename parameter in CompleteSubTask back to completedAt to match backend https://github.com/donetick/donetick/issues/224

commit decf25006bf9fd6bafd086e0c15d0eef88af12d1
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jun 1 22:19:58 2025 -0400

    feat: Implement StatusBarManager and useStatusBar hook for theme-aware status bar handling

commit f58003b4ce2b1a77eef24b59126d5e329770e05c
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jun 1 21:06:01 2025 -0400

    fix: Update CapgoCapacitorSocialLogin to version 7.6.3 and update Podfile.lock checksums

commit 6a13eef8e2167c9977b4a25cf09f2e236b986146
Merge: cd49d9a 6080b57
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jun 1 00:48:18 2025 -0400

    Merge branch 'main' into donetick.com

commit cd49d9a6a7ed2c91c9016c66002aad35cb9ab3d1
Merge: 4826090 ddf654a
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jun 1 00:48:07 2025 -0400

    Merge branch 'dev' into donetick.com

commit 4826090a903c838e3c6a6a9c7843a2785600097a
Merge: 89196b0 bf8e187
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat May 31 19:40:43 2025 -0400

    Merge branch 'main' into donetick.com

commit 89196b0b3f0438387c69ba23de64822faf4596d5
Merge: 7919b00 87a0039
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat May 31 03:43:07 2025 -0400

    Merge branch 'main' into donetick.com

commit 7919b00cae6f6d77795b88f380ebde911b7c1a61
Merge: 54c9819 ee69009
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat May 31 01:44:39 2025 -0400

    Merge branch 'main' into donetick.com

commit 54c981997e055e1de46d08cf408b78ecf569233e
Merge: c3b54d0 a217740
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Fri May 16 21:18:11 2025 -0400

    Merge branch 'main' into donetick.com

commit c3b54d049aff67df2a0fd11a01ee44a6797ff7c7
Merge: 206302b de4dc9b
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Fri May 16 20:48:22 2025 -0400

    Merge branch 'main' into donetick.com

commit 206302b2d2d4058a18457bb9bee45b1a6e13a65f
Merge: 56179a0 7ae2859
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Fri May 16 20:39:12 2025 -0400

    Merge branch 'main' into donetick.com

commit 56179a027f4510d3f5278fc649ecf1560d923aa1
Merge: 8980c06 e26f291
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Apr 24 22:11:20 2025 -0400

    Merge branch 'main' into donetick.com

commit 8980c06554b2c2eeb95e8063830f2461c732b70a
Merge: f8812ca 0b1208a
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Apr 24 21:56:39 2025 -0400

    Merge branch 'main' into donetick.com

commit f8812cadee1547a9bf70ba8e35201bd68081c05d
Merge: 4eaa68b 261919f
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Apr 24 21:35:26 2025 -0400

    Merge branch 'main' into donetick.com

commit 4eaa68bf6e91f81b87ac8c70615a6e4373291ee0
Merge: c2544d9 66db280
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Apr 24 19:52:10 2025 -0400

    Merge branch 'donetick.com' of https://github.com/meauxt/donetick-frontend into donetick.com

commit c2544d91e64e7d1f9db5c70fb12ce08bb0b76000
Merge: 6978288 f537a00
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Apr 24 19:51:43 2025 -0400

    Merge branch 'main' into donetick.com

commit 66db28044faa1f88122d51d7e0646622025ef38f
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Apr 24 02:52:34 2025 -0400

    fix: update Capacitor dependencies and downgrade CocoaPods version

commit 697828837e28a0a553092f99684376a9fc181902
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Apr 24 02:42:16 2025 -0400

    fix: update Java version to 21 and add new Capacitor dependencies

commit 3dc779fd15bbd7317be7e2bef0e741d21843341b
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Apr 24 02:37:13 2025 -0400

    fix: update Java version to 17 and add CapacitorCommunitySqlite and CapacitorNetwork dependencies

commit 6dbca55da82398a069d901bc3a85206fa47eae47
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Apr 24 02:22:07 2025 -0400

    chore: update dependencies

commit 0c163d52aefb2065abc38718c3d842183aadc0e3
Merge: e08b80d f0e0c0e
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Apr 24 02:00:03 2025 -0400

    Merge branch 'smart-text-field' into donetick.com

commit e08b80d625248a4917a03549d452530e2eadbd8a
Merge: b0b0bcc 1b53a4d
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Mar 17 01:04:49 2025 -0400

    Merge branch 'main' into donetick.com

commit b0b0bcc4a9561ab829a3e55f4b344edf971bf5d6
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Mar 10 01:14:11 2025 -0400

    Update Podfile.lock and enhance Safe Area handling for Android platform

commit ff13ee112782bf963e892e8be36d95ed628b4d08
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Mar 10 00:34:28 2025 -0400

    Update Podfile.lock to reflect updated Capacitor dependencies and downgrade CocoaPods version

commit a7b756e1dbf6081c843457c31728fef3b1c6ec5f
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Mar 10 00:34:12 2025 -0400

    Enhance Android configuration and improve Safe Area handling in NavBar and App components

commit aeab3560f6778712d8899a83497599b6f608b9eb
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Mar 8 23:51:43 2025 -0500

    Prevent NavBar from rendering on landing page in native platforms

commit 4972f554f53225636042f8e9bee19fa11e81893c
Merge: 7a7eb25 98b1cb6
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Mar 8 00:14:41 2025 -0500

    Merge branch 'capacitor7' into c7-donetick.com

commit 98b1cb6e8a25ebfff3fe7aacf421ffe56399c14e
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Mar 6 17:39:06 2025 -0500

    Add iOS and Android assets; update dependencies and configurations

commit 7a7eb25f33d1f0c241221ece32a1842dbdddd57d
Merge: e369549 76ed927
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Wed Mar 5 22:04:50 2025 -0500

    Merge branch 'main' into donetick.com

commit e36954960c803d5aab41a4b3549791a4c809b9a1
Merge: 4907e0a 52b81cc
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Wed Mar 5 21:42:11 2025 -0500

    Merge branch 'main' into donetick.com

commit 4907e0af41cc2033c549bb9ef51124e582c963f0
Merge: 062bbbb ee566bd
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Wed Mar 5 21:06:45 2025 -0500

    Merge branch 'main' into donetick.com

commit 062bbbb9137954eb1ef2b3ff101513659d6c68cd
Merge: ac6988c cd1b556
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Wed Mar 5 20:56:11 2025 -0500

    Merge branch 'main' into donetick.com

commit ac6988c66c59d0fb0bc2982a6c20456448fce1ba
Merge: 2365b5e 6431e71
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Feb 25 23:41:03 2025 -0500

    Merge branch 'main' into donetick.com

commit 2365b5e0895c34cd3f31fca032d652d2630bdea5
Merge: f064993 4734819
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Feb 15 00:06:31 2025 -0500

    Merge branch 'main' into donetick.com

commit f0649931825e2812da508e75d80f275854461e53
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Feb 15 00:04:59 2025 -0500

    Fix https://github.com/donetick/donetick/issues/128

commit d98a324a890318dca2cf4fb371fd83b99830d602
Merge: d36a428 5c82fe4
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Wed Feb 12 22:27:36 2025 -0500

    Merge branch 'donetick.com' of https://github.com/meauxt/donetick-frontend into donetick.com

commit d36a42871e98bc94f5c56634859325a561727c15
Merge: b35f518 c06d5f1
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Wed Feb 12 22:27:19 2025 -0500

    Merge branch 'main' into donetick.com

commit 5c82fe4c3f07ee0faefd7c1ac90b4c419df33c23
Merge: b5a0076 5bf0724
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Wed Feb 12 00:32:16 2025 -0500

    Merge branch 'main' into donetick.com

commit b5a00763d75d6c599520250bcd511b17317fd8b9
Merge: c6e1f9c 2925267
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Feb 11 21:01:01 2025 -0500

    Merge branch 'main' into donetick.com

commit c6e1f9c935d9654d1fd0e6cb802f9eb9934f65c0
Merge: 6e3f223 cfc121b
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Feb 11 20:50:47 2025 -0500

    Merge branch 'main' into donetick.com

commit 6e3f223c6ce83690466c31de38d918698424efd8
Merge: d2beee5 e964985
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Feb 11 20:49:26 2025 -0500

    Merge branch 'main' into donetick.com

commit d2beee52a1a954b63902abc596b25e97447a3c54
Merge: b35f518 06519a0
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Fri Feb 7 00:42:16 2025 -0500

    Merge branch 'main' into donetick.com

commit b35f518b4e6e40b4e6b0c6f360ad258bd50a689e
Merge: c4121db b221f38
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Feb 2 20:48:54 2025 -0500

    Merge branch 'dev' into donetick.com

commit c4121dbae1c16cb7def7c07bafccc98c6255d1b4
Merge: 8cc6789 568f86a
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Feb 2 01:27:53 2025 -0500

    Merge branch 'dev' into donetick.com

commit 8cc678955bd0a8f1846a17ee8dc2c7597c62cdf0
Merge: 279bf05 4527b22
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Jan 21 15:24:34 2025 -0500

    Merge branch 'dev' into donetick.com

commit 279bf059c4ca2034802872f0b49eea0d73f8e7fd
Merge: 8c0ccc9 4e64d0b
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Jan 18 09:54:24 2025 -0500

    Merge branch 'dev' into donetick.com

commit 8c0ccc9d2cd1cbf101ef672134ad8980f4e7cd65
Merge: 629c1ce 9dc3edb
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Fri Jan 17 00:50:46 2025 -0500

    Merge branch 'dev' into donetick.com

commit 629c1cee0b9b591f6c33b23e557af079837f9b4e
Merge: 5adeae6 56f66e9
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Jan 16 01:02:14 2025 -0500

    Add useDebounce hook for debouncing input value
    s# Please enter a commit message to explain why this merge is necessary,

commit 5adeae661b402280f1f0b84e1416f3ffbfcb3410
Merge: 7309161 aa7f412
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Wed Jan 15 02:05:10 2025 -0500

    Merge branch 'dev' into donetick.com

commit 73091615cb21faca1325fad6bb10aa126de297aa
Merge: f6d86a9 da85caf
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Wed Jan 15 01:55:13 2025 -0500

    Add IconButtonWithMenu component with label support
    Add LearnMoreButton with some instruction on task modal# Please enter a commit message to explain why this merge is necessary,

commit f6d86a92d92a5cf0b78c3505fc0b4de9917a8913
Merge: 89824a4 d3b3623
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Jan 14 11:08:22 2025 -0500

    Make sure the title respect upper and lower case

commit 89824a4ce0f374b0f41943d0c2b4d11bd234cc85
Merge: 9110bf6 cc11a62
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Jan 14 10:47:13 2025 -0500

    Experiment: Add Sidepanel with calendar view
    Support redeem points
    Experiment: task in sentences
    Fix small bugs in the chip when loading the chore card

commit 9110bf6de4a1a234dbd73afc19f78e4378816cc4
Merge: 4879b86 46f7f51
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Fri Jan 10 00:38:38 2025 -0500

    Update Login URL

commit 4879b86e49525da56de3f95d386711cc2013a5e2
Merge: f8d3312 13bfe66
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Fri Jan 3 02:12:21 2025 -0500

    Update API URLs to include version number

commit f8d3312ee7f333c190526b90e2e1534a9ab88379
Merge: 92513aa 1b1da5f
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Dec 31 02:23:06 2024 -0500

    Merge branch 'dev' into donetick.com

commit 92513aafaee2ed5135f022c57354ee63160a4f38
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Dec 29 00:31:10 2024 -0500

    chore: Remove unused import and fix typo in LabelView.jsx

commit aafc3c412db13f01b467df8180231fd58e2fd14d
Merge: 8183792 d4c36e2
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Dec 28 18:53:53 2024 -0500

    Initial Activity View
    Add New Colors.jsx
    Allow Dark model Toggle from the Navbar

commit 818379211ccde58532242aba17b6a88696df43ac
Merge: 7bdc09d 0f2781f
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Dec 26 19:06:20 2024 -0500

    Merge branch 'dev' into donetick.com

commit 7bdc09db7368d022c2552f1721d3fa3b52e8a795
Merge: 08955e3 577791b
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Dec 26 18:44:32 2024 -0500

    Merge branch 'main' into donetick.com

commit 08955e325e300411ebb113f80ef5be7e9898ecf5
Merge: f812ada 6085ffa
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Dec 26 18:28:20 2024 -0500

    Merge branch 'donetick.com' of https://github.com/meauxt/donetick-frontend into donetick.com

commit f812ada34938998d1a1cd4c00405b96edd7d219b
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Dec 26 18:22:15 2024 -0500

    Update npm dependency to latest stable version

commit bda85c8f90fd616deee9594b64cc02bb60af7d7c
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Dec 26 18:21:46 2024 -0500

    Update API_URL in Config.js to use window.location.hostname for 'AUTO' value

commit 1bda13166c569f0d726e3d40eb15e4ec3784188e
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Dec 26 02:39:16 2024 -0500

    feat: Set maximum file size to cache in service worker configuration

commit 6085ffa7e11844876cfdf3617c6efdd6ee741cbf
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Dec 26 02:37:19 2024 -0500

    Update Vite configuration to set maximum cache file size and remove unused Rollup external dependencies

commit 2d7ff4550e6f80529d11f4f7bf308873511b6a63
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Dec 26 02:32:06 2024 -0500

    Fix formatting in Vite configuration file

commit 47571fe092c915119ed700e437f616377f86e815
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Dec 26 02:30:56 2024 -0500

    Add external dependency configuration for Rollup in Vite build

commit 528faaf46cf780c0ce04a9380283a3a2d11825aa
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Dec 26 02:25:02 2024 -0500

    Remove unnecessary 'dev' flags from package-lock.json dependencies

commit 7d01541aecbe059f22c0c108b2baf81012eb3b36
Author: Mohamad Tarbin <mhed.t91@gmail.com>
Date:   Thu Dec 26 02:21:36 2024 -0500

    Mobile app (#3) (#4)

    * Initial Capacitor Config and plugins

    * Add Android project files and resources

    * Add local notification scheduling for chores

    * Add NotificationAccessSnackbar component for handling notification preferences

    * Add capacitor-preferences to Android project

    * Update notification Snackbar

    * Add local notification scheduling for chores

    * Add ionic.config.json file for custom project configuration

    * chore: Add environment variables for production deployment

    * Add Support for IOS, pass notificaiton token(push notifications)

    * Add Capacitor Device support and refactor notification handling

    * Refactor GoogleAuth client IDs to use environment variables

    * Remove google-services.json to enhance security by eliminating sensitive data from the repository

    * Remove environment files to enhance security by eliminating sensitive data from the repository

    * Rename project from fe-template to Donetick in ionic.config.json

    * Remove GoogleService-Info.plist and Info.plist to enhance security by eliminating sensitive data from the repository

    ---------

    Co-authored-by: Mo Tarbin <mohamad@Mos-MacBook-Pro.local>

commit 4aa4528b565560a6a91b9e2a9bdeda11dba7c2cf
Merge: bcd32a8 5d1f381
Author: Mohamad Tarbin <mhed.t91@gmail.com>
Date:   Thu Dec 26 02:18:13 2024 -0500

    Merge branch 'donetick.com' into dev

commit 5d1f3811c65445cae702660023bb449a8e221a53
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Dec 26 02:09:04 2024 -0500

    Add Info.plist configuration for iOS app

commit 903e8c3f1ec3e12041c9382936fcd16de7918d81
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Dec 26 02:08:28 2024 -0500

    Add Google services configuration for iOS app

commit 592a43a85c8540978c6b85d4a3bd01a643f607cc
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Dec 26 01:40:17 2024 -0500

    Add Google services configuration for Android app

commit 6ed89f0d085812364af0fd249e5c867a6e7b446d
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Dec 26 01:20:30 2024 -0500

    Add Android and iOS client IDs to production environment variables

commit a941263debcac8205ca828ee643c2a4dafa4d7ce
Merge: 385d923 1e7b47e
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Dec 22 16:07:18 2024 -0500

    Merge branch 'dev' into donetick.com

commit 385d92316ab6c4b20569a6d0e4f1fa2d5228c0b3
Merge: 22abf46 88c11ee
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Dec 15 18:11:00 2024 -0500

    Fix Unable to assign Assignee to task
    Support Loading  archived

commit 22abf462f041384559fa9808a24d308c40bf1fba
Merge: 08ccd89 7ea0a03
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Dec 14 02:15:21 2024 -0500

    Support Sortinging in My Chore by Date
    Show API Token and allow manual copy
    Show Error when sign up disabled
    Support Pushover

commit 08ccd891b115a599eb907d859a0129695baf5f01
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Dec 7 15:26:11 2024 -0500

    Update VITE_APP_API_URL in .env.production

commit 874898be4a13d5f16512f469c57cab2e4f9d4d46
Merge: 0994f3a f8639be
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Fri Dec 6 01:30:41 2024 -0500

    Merge branch 'dev' into donetick.com

commit 0994f3a0d3c05a2515084e455e950773526f3243
Merge: 7205a64 57b2ea1
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Nov 30 02:15:54 2024 -0500

    Merge branch 'main' into donetick.com

commit 7205a647677df61fa26b4428bac34e2d468defe1
Merge: 2514205 ba75962
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Nov 30 00:46:06 2024 -0500

    Add Label filters, Update cohre card to show labels, fix typo

commit 2514205e342e7196b8cd6ed8bbcdc2e53eca8889
Merge: f5d157d 7551871
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Nov 24 00:50:00 2024 -0500

    Merge branch 'dev' into donetick.com

commit f5d157d1758a92ec38fe89e894e5ef58af204ec6
Merge: b9b0d28 43608a3
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Nov 23 21:42:52 2024 -0500

    Merge branch 'dev' into donetick.com

commit b9b0d28a18affcbccf6b0b02401d6ee65ce62f22
Merge: d80311a 7c36e2d
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Nov 23 20:26:14 2024 -0500

    Add Support for LabelV2, Add LabelModal and LabelView.
    Add React Query

commit d80311ac956412f8a22d43cab445d4c928201048
Merge: 5954dfc 2ad8ddd
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Nov 4 00:23:13 2024 -0500

    Fix Monthly text

commit 5954dfcf500a88b7a2ec5c7004b545febf4327c2
Merge: 1925822 e1615d2
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Nov 3 22:59:43 2024 -0500

    Merge branch 'dev' into donetick.com

commit 1925822192ff22de00a76fc2fafa6dfd174c8406
Merge: 7465158 1e90c2e
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Nov 3 22:40:43 2024 -0500

    Update the version

commit 7465158b033a330ea9d933d787f03779ba754abe
Merge: 5a16acf ee5763b
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Nov 3 22:38:02 2024 -0500

    Add Support for Priority

commit 5a16acf403e5d0fd173f411f91ddbfc8b15e9168
Merge: d85776d 2406331
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Fri Sep 6 18:05:54 2024 -0400

    Add CookiePermissionSnackbar
    Update landing

commit d85776d8fd9cb8a007128ad49a87a3da941e9295
Merge: 78c8bb7 7e93e80
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Aug 10 02:31:27 2024 -0400

    Merge branch 'dev' into donetick.com

commit 78c8bb7a873ea6c596855a785a20f360724d15f4
Merge: fb93f4e ea4783f
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Aug 10 02:29:35 2024 -0400

    Merge branch 'dev' into donetick.com

commit fb93f4e705b2988cd21194be28eceb9e8bae27df
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Aug 4 22:36:22 2024 -0400

    chore: Add support for Open Replay

commit dc9760960c2dbfe04ab0abe182493dc702ebc788
Merge: f003eca b5f17dc
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Aug 4 22:35:12 2024 -0400

    Add support for Open Replay

commit f003eca86b664564c0519415898456e28765f5db
Merge: eeb0e20 539cf5c
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Jul 29 12:46:40 2024 -0400

    Merge branch 'dev' into donetick.com

commit eeb0e209a3cb175fc63d1d0894f6d0c1039183a8
Merge: 65fd025 8e0c467
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Jul 29 12:10:31 2024 -0400

    Merge branch 'dev' into donetick.com

commit 65fd025b26cef1cdb632732b5ef1656df10fe9bc
Merge: 098c2bd ff745e9
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Jul 29 12:03:43 2024 -0400

    Merge branch 'dev' into donetick.com

commit 098c2bde3755d97f6eb3585bbce6b9766f313987
Merge: 65a6eae 0df5162
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Jul 29 12:00:49 2024 -0400

    Merge branch 'dev' into donetick.com

commit 65a6eae42ea00ec0c1e043f0d3580f7bbcfa12ad
Merge: f676bf0 b7ee1c0
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Jul 29 02:55:28 2024 -0400

    Merge branch 'dev' into donetick.com

commit f676bf0aaa356b4a414199b364787e36bd757c23
Merge: f365635 90efb5b
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Jul 20 03:40:53 2024 -0400

    Merge branch 'dev' into donetick.com

commit f3656353cd95276b23d9f7aba0f177ee4d81a89e
Merge: 3036eb4 aed179d
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Jul 18 18:20:23 2024 -0400

    Merge branch 'dev' into donetick.com

commit 3036eb443a0ff8b09d4a33c4c6842082ab6edad9
Merge: e2dff21 7991399
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Thu Jul 18 18:06:56 2024 -0400

    Merge branch 'dev' into donetick.com

commit e2dff2197c5a49e97fd9f8150d336fdd5b11afb3
Merge: c292335 dfe89b4
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Wed Jul 17 01:08:35 2024 -0400

    Merge branch 'dev' into donetick.com

commit c292335e95e7aa01ab0960ac4e1c080ceeda1379
Merge: 9602842 7f4e592
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Jul 16 19:37:32 2024 -0400

    Merge branch 'dev' into donetick.com

commit 9602842008a9cb76022640b370e941208f08305d
Merge: 9cba371 93512eb
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Jul 16 01:59:02 2024 -0400

    Merge branch 'dev' into donetick.com

commit 9cba371fd526f2a52dcef83d20e463c446852e1d
Merge: ef6c184 7a49011
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jul 14 17:56:25 2024 -0400

    Merge branch 'dev' into donetick.com

commit ef6c1841fe4c4ebffca920779f04f8c92b18ffe6
Merge: 78299ee bc741d9
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jul 14 17:45:41 2024 -0400

    Merge branch 'd`ev' into donetick.com

commit 78299ee953418059c84b4b9ea53ffe01129a28fc
Merge: bcc82f9 ba3331e
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Jul 13 01:54:35 2024 -0400

    Merge branch 'dev' into donetick.com

commit bcc82f9b524a484a41ac4470d123c565aafd9ce8
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Jul 9 21:22:32 2024 -0400

    Add VITE_IS_LANDING_DEFAULT flag for conditional rendering of landing page

commit 48d664e15704811c60d125370e5bd80ecf6cfb8b
Merge: 8f670c6 e25a6d3
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Jul 9 21:21:43 2024 -0400

    Merge branch 'dev' into donetick.com

commit 8f670c60bf8df7e060b8a963b5a107e6f59e3b93
Merge: 851c330 8da220e
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Jul 9 17:51:09 2024 -0400

    Merge branch 'dev' into donetick.com

commit 851c33035c8a0431d36524a300b5fd3b399238ce
Merge: 5a60894 40f1384
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Jul 9 17:41:23 2024 -0400

    Update landing Merge branch 'dev' into donetick.com

commit 5a6089465391825c9b0278e2dc330aff8167ae36
Merge: 499da8f c4bf06b
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jul 7 19:49:37 2024 -0400

    Merge branch 'dev' into donetick.com

commit 499da8f995ea10ae4a488e2b83505460a925de8d
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jul 7 03:19:03 2024 -0400

    Squashed commit of the following:
        Trim first character from emoji name in ChoreCard component

commit d031363dae6789b2ea8bd0cd770ccdeb98bdb7d7
Merge: a725dc2 09a4bbd
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jul 7 02:50:39 2024 -0400

    Merge branch 'dev' into donetick.com

commit a725dc2d5f22575bbdadc278b986e8575ee74a97
Merge: 468f282 8a919dd
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jul 7 02:14:02 2024 -0400

    Merge branch 'dev' into donetick.com

commit 468f282f2e2cb5bb73c8542d8135b2cdf3981d80
Merge: 47f8218 e039b73
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jul 7 00:25:27 2024 -0400

    Merge branch 'dev' into donetick.com

commit 47f82188a4fbba5bffcf1d50bde30e19c10354e3
Merge: dd5f61a 4f9e2f9
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Jul 6 13:24:57 2024 -0400

    Merge branch 'dev' into donetick.com

commit dd5f61a3c13f528275dedf0af4dbe8aa5923b990
Merge: 203846b ae96328
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Jul 6 03:50:05 2024 -0400

    Merge branch 'dev' into donetick.com

commit 203846ba3220732ec619f39cb9ea60e999a6115e
Merge: 7f86704 09c25ce
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sat Jul 6 02:35:20 2024 -0400

    Merge branch 'dev' into donetick.com

commit 7f8670439b044eb38acfa5bfa036166c647d5b15
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Fri Jul 5 17:30:47 2024 -0400

    refactor: Simplify API_URL assignment in Config.js

commit 24d9db8d580224574d6c468150b638c9e29f2528
Merge: 6232455 c34da50
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Fri Jul 5 17:29:45 2024 -0400

    Merge branch 'dev' into donetick.com

commit 6232455f30692e6e6ca8351049d6985b158cf9fe
Merge: 6da9c29 c5ee02d
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Tue Jul 2 00:49:58 2024 -0400

    Merge branch 'dev' into donetick.com

commit 6da9c2966b2ba5b168844a2961f169e188bafa84
Merge: 0b90929 61b4e4b
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Jul 1 23:54:30 2024 -0400

    Merge branch 'dev' into donetick.com

commit 0b909292d6c033662ef8a6591dd8d665611d88ab
Merge: 4546728 5e54da8
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Jul 1 22:13:01 2024 -0400

    Merge branch 'dev' into donetick.com

commit 45467286b27fc7dd9cbb05947d7db2ca81312da0
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Mon Jul 1 01:52:00 2024 -0400

    add the .env.development file

commit 73a458b740cc81376ef3d28e80ac931865d2af0a
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jun 30 23:08:23 2024 -0400

    navigate app always to my/chores

commit 44aeb03c53c30ac5644461bc45e0d8c49b01911a
Author: Mo Tarbin <mhed.t91@gmail.com>
Date:   Sun Jun 30 22:46:55 2024 -0400

    Add production environment variables for API URL, redirect URL, and Google Client ID
2026-05-30 21:50:16 -04:00
tanomitsu
08f3928ebc feat: add Japanese (ja) localization
- Add ja translations for common, settings, and chores namespaces
- Register ja in AVAILABLE_LANGUAGES so it appears in the language picker
- Import moment/locale/ja so date and relative-time formatting uses Japanese
2026-05-26 15:28:29 +09:00
Mohamad Tarbin
350c177be8 Merge pull request #109 from donetick/improve-parser-logic
Enhance due date parsing by validating word boundaries
2026-05-26 01:07:56 -04:00
Mohamad Tarbin
d3103cb966 Merge pull request #110 from donetick/offline-support-v2.2
Implement offline support for chore archiving and unarchiving
2026-05-26 01:07:38 -04:00
Mo Tarbin
eec3721e9d refactor: update offline support notifications and confirmation messages for clarity 2026-05-26 00:02:10 -04:00
Mo Tarbin
8058f8f376 feat: implement offline support for chore archiving and unarchiving, enhance state management for pending commands 2026-05-25 16:51:34 -04:00
Mo Tarbin
eae67fd482 Refactor date parsing logic to validate word boundaries, preventing partial matches for days and months 2026-05-25 16:47:05 -04:00
Mo Tarbin
d10727b87d Enhance due date parsing by validating word boundaries to prevent partial matches 2026-05-25 12:46:18 -04:00
Mohamad Tarbin
52d6dc9376 Merge pull request #106 from Paccoco/fix/android-custom-server-url-init
fix: reinitialize api client after server URL changes
2026-05-25 02:01:02 -04:00
Mohamad Tarbin
6ff38e8068 Merge pull request #90 from felipellc/add-pt-br-translation
feature/add-ptbr-support
2026-05-25 01:59:06 -04:00
Mohamad Tarbin
b54f4a846c Merge pull request #99 from donetick/offline-support-v2
Offline support v2
2026-05-25 01:57:27 -04:00
Mo Tarbin
b69fa34b9f including improved command handling and sync status updates 2026-05-25 01:56:14 -04:00
Mohamad Tarbin
e1f050ac7e Merge pull request #107 from donetick/fix-activity-car
Add status handling for 'Missed' and 'Rescheduled' activities in Acti…
2026-05-25 01:48:21 -04:00
Mo Tarbin
76668b65fc Add status handling for 'Missed' and 'Rescheduled' activities in ActivityItem 2026-05-24 01:54:56 -04:00
Paccoco
7524cc31c1 fix: reinitialize api client after server URL changes 2026-05-24 01:53:14 +00:00
nick
a7f832107d Use common storage function to save access and refresh tokens 2026-05-17 19:49:08 +00:00
Mohamad Tarbin
674b0d7285 Merge pull request #101 from MindStudioOfficial/fix/points-members-history-v2
[reopen] fix: points history to include circle members [for donetick/donetick#362]
2026-05-16 22:42:12 -04:00
Mo Tarbin
d618a09f6d add network listener management and enhance sync on reconnect functionality 2026-05-16 19:33:07 -04:00
Marc Julien Bach
995b1fe63c Fix points history to include circle members 2026-05-16 16:06:09 +02:00
Mohamad Tarbin
6200f4f790 Merge pull request #100 from donetick/revert-93-fix/points-members-history
Revert "fix: points history to include circle members [for donetick/donetick#362]"
2026-05-16 00:46:10 -04:00
Mohamad Tarbin
a16c312292 Revert "fix: points history to include circle members [for donetick/donetick#362]" 2026-05-16 00:45:51 -04:00
Mohamad Tarbin
1d907bc2d4 Merge pull request #93 from MindStudioOfficial/fix/points-members-history
fix: points history to include circle members [for donetick/donetick#362]
2026-05-16 00:45:44 -04:00
Mohamad Tarbin
d267ba4cde Merge pull request #94 from tinect/feat/germanTranslation
feat: add German translation
2026-05-12 01:25:09 -04:00
Mo Tarbin
07c31ebde1 feat: enhance chore management with history and sync improvements
- Added support for starting and pausing chores with offline handling.
- Implemented chore history updates and deletions with pending command management.
- Enhanced sync engine to handle chore history changes and deletions.
- Introduced a PendingBadge component to display pending actions for chore history.
- Updated DeveloperSettings to include sync diagnostics and reset functionality.
- Improved user notifications for offline actions and pending commands.
- Refactored ChoreView to dynamically generate info cards based on chore history.
- Added sync status indicator with cancel all functionality for pending commands.
2026-05-12 01:10:49 -04:00
Mo Tarbin
2c353628a3 feat: implement offline support for labels and projects, enhance advanced settings with offline feature toggle, and add sync status indicator
- Added offline support for fetching and caching labels and projects using `offlineDB`.
- Enhanced `AdvancedSettings` to include an offline feature toggle with confirmation modal for disabling offline support.
- Introduced `SyncStatusIndicator` component to display sync status, pending commands, and failed commands.
- Created `PendingBadge` component to manage and display pending actions for synchronization.
- Removed deprecated offline mode toggle from `StorageSettings`.
- Improved error handling and user notifications for offline actions and sync processes.
2026-05-11 17:27:29 -04:00
Mohamad Tarbin
3d170d88fb Merge pull request #88 from hoborm/bugfix/filters-hide-grouping
Add support for grouping to custom filtered chores
2026-05-03 21:30:38 -07:00
Mohamad Tarbin
90171b2ebd Merge pull request #89 from hoborm/bugfix/filters-and-chips-navigation-hamburger
Navigation of filters and chips is now in place instead of navigation to a new site in PWA.
2026-05-03 21:27:01 -07:00
tinect
36298893db feat: rename “Lokalisierung” to “Sprach- und Formateinstellungen”; keep “Things” untranslated 2026-04-21 09:07:06 +02:00
tinect
ca7d71eed4 feat: add German translation 2026-04-20 21:24:59 +02:00
Marc Julien Bach
d0e2771a2f Fix points history to include circle members 2026-04-18 04:39:28 +02:00
Felipe Camargo
6b80bc5b5e Rename pt-BR locale to pt to match project convention
All existing locales use two-letter codes (ar, en, es, fr, nl) and the
crowdin.yml output path uses %two_letters_code% — using pt-BR would
conflict with any future Crowdin-imported Portuguese.

The display name stays 'Portuguese (Brazil)' / 'Português (Brasil)' so
users still see it's the Brazilian dialect.
2026-04-13 08:08:38 -07:00
Felipe Camargo
016a613fd5 Add Brazilian Portuguese (pt-BR) translation
Adds public/locales/pt-BR/ with complete translations for common,
chores, and settings namespaces. Registers pt-BR in the
AVAILABLE_LANGUAGES picker in LocalizationContext.jsx.

Tone: informal 'você' form, natural Brazilian Portuguese.
2026-04-13 07:49:34 -07:00
Mo Tarbin
c6865f48f5 Merge branch 'main' of https://github.com/Donetick/frontend 2026-04-12 14:09:01 -04:00
Mo Tarbin
3935bd67f8 Sort months in recurrent chip text for consistent display 2026-04-12 14:08:45 -04:00
Mohamad Tarbin
917993a4fa Merge pull request #87 from hoborm/bugfix/filters-settings-icon-misaligned
Add 32px height for filter chip, align cogwheel with filters
2026-04-12 14:02:46 -04:00
Mihaly Hobor
1d807002f8 Navigation of filters and chips is now in place instead of navigation to a new site in PWA. 2026-04-09 02:56:38 +02:00
Mihaly Hobor
f95e1138a0 Add support for grouping to custom filtered chores 2026-04-09 02:45:57 +02:00
Mihaly Hobor
1d16d74383 Add 32px height for filter list, align cogwheel with filters 2026-04-09 01:35:49 +02:00
Mo Tarbin
4713e99c7b Bump version to 1.2.2 and update project version codes 2026-04-07 00:43:08 -04:00
Mo Tarbin
1e122b36a3 Merge branch 'main' of https://github.com/Donetick/frontend 2026-04-07 00:37:29 -04:00
Mo Tarbin
c87335ff56 Bump version to 1.2.1 and update project version codes 2026-04-07 00:05:02 -04:00
Mohamad Tarbin
b8dd0e2fb1 Merge pull request #73 from donetick/feature/internationalization-support
Feature/internationalization support
2026-04-06 21:29:31 -04:00
Mohamad Tarbin
3a754d5703 Merge pull request #85 from gitbreaker222/patch-1
UX / SECURITY: Update placeholder text for displayName input
2026-04-06 21:17:42 -04:00
gitbreaker222
e39fa172cb Update placeholder text for displayName input
Currently new users are asked to put their pw into the displayName input --> reveiling credentials!!
2026-04-06 18:39:43 +02:00
Mohamad Tarbin
8c0d2b67e4 Merge branch 'main' into feature/internationalization-support 2026-04-05 20:51:29 -04:00
Mohamad Tarbin
12cba1f8fb Merge pull request #81 from hoborm/bugfix/complete-chore-reappear-issue
Chore hides then reappears after completion
2026-04-05 20:49:09 -04:00
Mohamad Tarbin
bf5ae30bda Merge pull request #83 from donetick/04052026-fixes
bug fixes
2026-04-05 20:43:50 -04:00
Mo Tarbin
2973b47555 User Activities to support note viewing functionality 2026-04-05 20:41:16 -04:00
Mo Tarbin
65cba31306 Update due date handling to treat 23:59:59 as end-of-day and adjust parsing logic for unspecified times 2026-04-05 20:27:07 -04:00
Mo Tarbin
629920c2b3 Description not being send with TaskinSentence 2026-04-05 20:26:51 -04:00
Mo Tarbin
e0f00fd4f5 Enhance AddTaskModal to support custom due times and update due date handling 2026-04-05 18:44:41 -04:00
Mo Tarbin
083680b563 ChoreHistoryItem to improve status icon handling and update date parsing logic to match choreHistory card 2026-04-05 18:27:37 -04:00
Mo Tarbin
9a637c484b fix issue if we use Reset Filter showing task across project instead of default only 2026-04-05 18:27:07 -04:00
Mo Tarbin
175ef04c70 Fix SmartTaskTitleInput to set text color to transparent for better visibility in dark mode 2026-04-05 18:25:55 -04:00
Mihály Hóbor
1d11f8316c Fix the issue where the chore reappears after completion then becomes hidden again. 2026-04-04 01:06:18 +02:00
Mohamad Tarbin
bb8027d663 Merge pull request #64 from feedingaliencat/chores-filter-available-for-me
Chores filter: Add filter for "Assigned to me or not assigned"
2026-04-02 23:56:24 -04:00
Mohamad Tarbin
bfa5c66006 Merge pull request #79 from hoborm/bugfix/rework-create-chore-notification-input-v2
Fix issue where cannot delete input field before input
2026-04-02 23:54:25 -04:00
Mihály Hóbor
0a606f6d23 Fix issue where cannot delete input field before input 2026-04-02 16:08:59 +02:00
emilio
e4611508ca Merge pull request #1 from hoborm/patch-1
Update label for quick filter to 'Available for me'
2026-04-01 12:14:01 +02:00
Mihaly Hobor
3a8ac8298d Update label for quick filter to 'Available for me' 2026-03-31 00:45:05 +02:00
Mohamad Tarbin
6ab6d0d205 Merge pull request #63 from feedingaliencat/readme-point-to-backend-docs
README: Point to the full documentation in backend
2026-03-30 01:19:38 -04:00
Mohamad Tarbin
30d398f5f1 Merge pull request #69 from hoborm/bugfix/deleted-task-view-no-update
Fix chore list view doesn't update when chore is deleted.
2026-03-30 01:09:48 -04:00
Mohamad Tarbin
85de7d08fd Merge pull request #74 from feedingaliencat/588-chores-starting-with-digit
ChoreCard: Fix rendering of chores names starting with a digit
2026-03-30 01:08:57 -04:00
Mohamad Tarbin
9f9724ce36 Merge pull request #75 from GilDev/patch-1
Fix typo "notification"
2026-03-30 01:08:16 -04:00
Mohamad Tarbin
264acd0532 Merge pull request #77 from Vi-Ku/fix/hide-signup-when-disabled-602
fix: hide Create new account button when signup is disabled
2026-03-30 01:07:47 -04:00
Mohamad Tarbin
7a495c9bd6 Merge pull request #78 from hoborm/bugfix/rework-create-chore-notification-input
Rework notification input fields, fix verification happening early
2026-03-30 01:05:15 -04:00
Mihály Hóbor
42549bf1a6 Rework notification input fields, fix verification happens too early. Adjust ranges. 2026-03-28 02:41:13 +01:00
vi-ku
56c97001fa fix: hide Create new account button when signup is disabled
When is_user_creation_disabled is true in the /resource API response,
hide the 'Create new account' button on the login page entirely instead
of showing it and blocking with an error after the form is filled.

Fixes: donetick/donetick#602
2026-03-27 20:35:13 +05:30
Mo Tarbin
4ad8b1aef8 Fix https://github.com/donetick/donetick/issues/604 Enhance ChoreEdit component with dropdown for archive/unarchive actions and add delete option 2026-03-24 17:04:25 -04:00
Mo Tarbin
92e8160505 Fix https://github.com/donetick/donetick/issues/611 on-time check in ActivityItem to handle missing dueDate 2026-03-24 16:51:57 -04:00
Mo Tarbin
0b19cdc95c Add 'Missed' and 'Rescheduled' statuses to ChoreHistoryStatus and update related components 2026-03-23 22:31:59 -04:00
Mo Tarbin
c4b6674492 Add '/password/update' to public pages in NavBar component to allow password reset 2026-03-23 22:31:17 -04:00
Mo Tarbin
cd2fa7943b Refactor chore selection logic to pass 'chores' parameter to getSelectedChoresData in bulk actions 2026-03-23 22:30:56 -04:00
Gilles Devillers
6245f25b7c Fix typo "notification" 2026-03-17 10:52:50 +01:00
Mo Tarbin
3c29d4a19f Merge branch 'dev' 2026-03-15 23:48:29 -04:00
Mo Tarbin
f917952083 revert completion window back to hours 2026-03-15 23:48:07 -04:00
Mo Tarbin
6fe22a5fa4 Reset project and filters on search filter clear in MyChores component 2026-03-15 23:37:52 -04:00
Mo Tarbin
8ea12399d3 Change button variant to 'outlined' for active insights in SmartInsightsCard 2026-03-15 23:09:38 -04:00
Mo Tarbin
2947d9aeec Remove Deadline for now as i want to spend more time thinking about it. as of now it's not tied to anything anyway 2026-03-15 23:09:38 -04:00
Mo Tarbin
17551f813b Fix https://github.com/donetick/frontend/issues/72 Add styles to prevent iOS Safari auto-zoom on input focus in index.css and RichTextEditor.css 2026-03-15 23:09:38 -04:00
Mo Tarbin
8022a0cd92 Change button variant to 'outlined' for active insights in SmartInsightsCard 2026-03-15 23:08:09 -04:00
Mo Tarbin
e5edaeb147 Remove Deadline for now as i want to spend more time thinking about it. as of now it's not tied to anything anyway 2026-03-15 23:07:16 -04:00
Emilio Veloci
4b1bd48487 ChoreCard: Fix rendering of chores names starting with a digit 2026-03-12 16:33:46 +01:00
Mo Tarbin
980a539ad2 Fix https://github.com/donetick/frontend/issues/72 Add styles to prevent iOS Safari auto-zoom on input focus in index.css and RichTextEditor.css 2026-03-11 22:26:42 -04:00
Mohamad Tarbin
cef329376b Merge branch 'main' into feature/internationalization-support 2026-03-10 23:10:48 -04:00
Mo Tarbin
230546d57f Remove Translation instruction 2026-03-10 23:04:05 -04:00
Mo Tarbin
b418ef0f99 Merge branch 'dev' of https://github.com/meauxt/donetick-frontend into dev 2026-03-09 01:10:14 -04:00
Mo Tarbin
343245f290 Add Smart Insights feature to Sidepanel and refactor SidepanelSettings 2026-03-09 01:10:00 -04:00
Mohamad Tarbin
5ec2db5dca Update Crowdin configuration file 2026-03-09 01:06:02 -04:00
Mohamad Tarbin
c21f4e1d2e Merge pull request #71 from donetick/dev
Fix multiselect issues and enhance chore management features
2026-03-09 00:02:37 -04:00
Mo Tarbin
a49404b877 Add Smart Insights feature to Sidepanel and refactor SidepanelSettings 2026-03-08 23:59:20 -04:00
Mo Tarbin
1982408881 Add scheduled notifications management to DeveloperSettings 2026-03-08 23:22:10 -04:00
Mo Tarbin
4e352e1430 Add app state change listener to manage focus state with React Query 2026-03-08 23:21:20 -04:00
Mo Tarbin
4fa0f5ffeb Refactor duration handling and enhance chore management features
- Replace hardcoded time units with TIME_UNITS constant in NotificationTemplate.
- Introduce DurationInput component for reusable duration selection in ChoreEdit and AddTaskModal.
- Update chore queries to refetch on window focus.
- Adjust completion window logic in ChoreView and HistoryCard for better deadline handling.
- Implement smart insights filter restoration in MyChores.
- Add MyChoreHeader component for improved filter display.
- Enhance activity notes display with truncation and modal view in ActivitiesCard.
2026-03-08 23:21:02 -04:00
Mo Tarbin
fc91894336 Refactor localization handling across components
- Updated LocalizationContext to consolidate date and time formatting functions into a single `fmt` object.
- Modified ChoreCardHelpers to accept a time format parameter for due date text.
- Adjusted ChoreView, RepeatSection, TimePassedCard, and other components to utilize the new `fmt` object for date and time formatting.
- Enhanced HistoryCard and TimerEditModal to use the new localization functions for consistent date and time display.
- Refined Settings and CircleSettings to leverage the updated localization methods for subscription and member date displays.
- Improved ThingsHistory and UserActivities to format dates and times using the new localization structure.
- Ensured CalendarCard and CalendarDual components utilize the new formatting functions for better readability.
2026-03-08 23:08:37 -04:00
Mo Tarbin
176f66b437 feat: Add French and Dutch localization support for common UI elements 2026-03-08 23:02:36 -04:00
Mo Tarbin
0a0a5bd60f feat: Add Saturday localization support in settings and update calendar type handling 2026-03-08 21:59:42 -04:00
Mo Tarbin
e5504e0bdf Complete ChoreView and Settings translation for ES and Arabic
- Add all missing translation keys to ChoreView component
- Replace hardcoded strings with i18n translation calls
- Complete Spanish (es) translations for ChoreView and Settings
- Complete Arabic (ar) translations for ChoreView and Settings
- Update ProfileSettings component with full translation support
- Add translations for notifications, confirmations, and UI labels
2026-03-09 01:15:33 +00:00
Mo Tarbin
220c068822 fix: Use formatDateTime instead of formatDate for nextDueDate in ChoreView
The formatDate function was being called with a boolean (true) as the format
parameter, which caused moment.js to throw 'format.match is not a function' error.
Changed to use formatDateTime() which properly formats both date and time.
2026-03-09 00:56:24 +00:00
Mo Tarbin
1214c17389 feat: Add RTL drawer support, translate ChoreView, and apply date format preferences
Navigation:
- Fix drawer to slide from right in RTL languages (Arabic, Hebrew)
- Add anchor prop based on isRTL flag
- Drawer now properly positioned for RTL languages

ChoreView Translations:
- Add comprehensive Arabic and Spanish translations for ChoreView
- Translate info cards (Assignment, Schedule, Statistics, Details)
- Translate notification messages (Task Completed, Undo, etc.)
- Translate action buttons and confirmation modals
- Translate timer-related modals (Reset Timer, Clear All Time Records)

Date Format Application:
- Replace hardcoded moment date formats with formatDate()
- Apply user's selected date format preference in ChoreView
- Due date chip now respects user's date format setting
- Dates display consistently according to user preference

All UI text in ChoreView now translates to Arabic and Spanish.
Navigation drawer slides from correct side for RTL languages.
2026-03-08 16:51:18 +00:00
Mo Tarbin
a82f6b16b7 feat: Add translations for navigation and settings overview, improve RTL support
- Add navigation translations (All Tasks, Archived, Things, etc.)
- Translate NavBar menu items and logout button
- Add comprehensive SettingsOverview translations
- Translate upgrade card and all settings sections
- Add ChoreView translations structure
- Improve RTL CSS support for better card alignment
- Fix flex, list, and container alignment for RTL languages

Navigation drawer now shows translated menu items in user's language.
Settings overview page fully translated.
RTL languages (Arabic, Hebrew) now have proper alignment for sidepanel cards.
2026-03-08 16:37:02 +00:00
Mo Tarbin
7f74574a7f fix: Add localization route and settings menu entry
- Add LocalizationSettings to RouterContext routes
- Add localization card to SettingsOverview menu
- Update LocalizationSettings to use SettingsLayout
- Add Language icon import

Now accessible at /settings/localization
2026-03-08 16:22:13 +00:00
Mo Tarbin
6d6185dc5e feat: Add comprehensive internationalization (i18n) support
- Add multi-language support with i18next and react-i18next
- Implement user-selectable date format preferences (5 formats)
- Add time format preferences (12-hour/24-hour)
- Implement RTL (right-to-left) support for Arabic, Hebrew, Persian, Urdu
- Add first day of week preference
- Create LocalizationContext for managing i18n settings
- Add LocalizationSettings component to Settings page
- Include sample translations: English, Spanish, Arabic
- Configure 10 languages: en, es, fr, de, ar, he, zh, ja, pt, ru
- Add translation management documentation and Crowdin config
- Create date formatting utilities that respect user preferences
- Add RTL CSS styles for proper layout mirroring
- Update Settings and ThemeToggle components to use translations
- Add comprehensive documentation (implementation guide, quick reference, translation guide)

All user preferences are persisted to localStorage and apply throughout the app.
2026-03-08 15:57:57 +00:00
Mo Tarbin
21e0b08716 Fix https://github.com/donetick/donetick/issues/576
tailwind.config.js — Added corePlugins: { preflight: false } to disable Tailwind's Preflight reset. Preflight forces svg { display: block } which breaks MUI Joy's inline icon layout inside <Select>, <Autocomplete>, etc., making the icon area unclickable. Since MUI Joy's <CssBaseline /> already provides a CSS reset, Preflight was redundant.

index.css — Removed the global button, a, [role="button"] { transform: translateZ(0); backface-visibility: hidden; } rule. This was creating new stacking contexts on every button element, which interfered with MUI Joy's internal pseudo-element overlays used for click-target expansion.
2026-03-07 23:25:02 -05:00
Mihaly Hobor
651a6d6b3d Fix chore list view doesn't update when chore is deleted. 2026-02-27 23:51:24 +01:00
Mo Tarbin
658054b13d Clear active filter when navigating to All Tasks When a filter was active and the user navigated to /chores
via the navbar, the activeFilterId state persisted even though the
  filterId
2026-02-23 01:40:20 -05:00
Mo Tarbin
58ebfb71d1 Fix unable to use multiselect
https://github.com/donetick/donetick/issues/544
2026-02-22 23:19:47 -05:00
Emilio Veloci
842fb976cd Chores filter: Add filter for "Assigned to me or not assigned"
Use case:
An user might want to work on the chores assigned to them or still not
assigned, whereas they might not be interested in the chores already
assigned to other users.
2026-02-21 18:05:02 +01:00
Emilio Veloci
8c28183410 README: Point to the full documentation in backend 2026-02-21 18:04:33 +01:00
Mohamad Tarbin
5ae1036f4d Merge pull request #51 from hoborm/bugfix/chorecard-assigned-self
Show chore assigned person even if it's our own.
2026-02-21 11:48:13 -05:00
Mohamad Tarbin
cf70854af5 Merge pull request #61 from wjzijderveld/password-length
Aligned password requirements and increased max-length to 64
2026-02-21 11:47:14 -05:00
Mo Tarbin
da1f7bea4f handleTaskCompletion to remove timeout and improve undo functionality 2026-02-18 01:08:59 -05:00
Mo Tarbin
a8180a04ab add NoteViewerModal and integrate note viewing functionality in HistoryCard 2026-02-18 00:19:33 -05:00
Mo Tarbin
55acdfba2a streamline EditHistoryModal layout and improve button placement 2026-02-18 00:19:15 -05:00
Mo Tarbin
4b4498e84d add NoteViewerModal for displaying chore notes and descriptions
Fix https://github.com/donetick/donetick/issues/532
2026-02-18 00:18:44 -05:00
Mo Tarbin
f483653506 show performer avatar in HistoryCard component 2026-02-16 18:27:52 -05:00
Mo Tarbin
6e3def2c13 Fix : skip rending when no entry selected
Add Support for notification when action happen
https://github.com/donetick/donetick/issues/471
2026-02-16 12:15:51 -05:00
Mo Tarbin
6416378b78 update package versions and remove deprecated react-swipeable-list dependency 2026-02-16 11:27:48 -05:00
Mo Tarbin
3591bce1b5 fix: clear selected project from local storage when the active project is deleted 2026-02-16 00:04:20 -05:00
Mo Tarbin
174a00c469 fix: update button label from 'Create Custom Filter' to 'Create Filter' in SortAndGrouping component 2026-02-16 00:02:15 -05:00
Mo Tarbin
f07cb350d4 fix: parse filter ID as number in MyChores component 2026-02-15 23:59:57 -05:00
Mo Tarbin
3d8fbe05f3 Shoe UserActivites even where there is no data 2026-02-15 23:28:54 -05:00
Mo Tarbin
1fc1d69dae feat: add MoreVert icon button for toggle actions in multiple components 2026-02-15 23:21:44 -05:00
Mo Tarbin
af401e7b27 refactor: replace react-swipeable-list with @meauxt/react-swipeable-list across multiple views 2026-02-15 23:17:09 -05:00
Mo Tarbin
bc274b2cf7 fix: update subscription modal navigation in UserProfileAvatar 2026-02-15 11:39:25 -05:00
Mo Tarbin
488c732f3c Unify the chip texts generator logic for chorecard 2026-02-15 11:39:05 -05:00
Willem-Jan
4d58e52729 Aligned password requirements and increased max-length to 64 2026-02-15 13:18:33 +01:00
Mo Tarbin
0b7d7bbe7f fix: update dependency array in AppContent useEffect to when to show there is update
https://github.com/donetick/donetick/issues/521
2026-02-14 16:58:03 -05:00
Mo Tarbin
75ac9fd38d bump version to 1.2.0 for Android, iOS, and package.json 2026-02-14 16:50:09 -05:00
Mo Tarbin
d8d7b6a766 Merge branch 'main' into dev 2026-02-10 23:21:33 -05:00
Mo Tarbin
aaa7bae55f force flow torecat for all screen 2026-02-10 23:21:27 -05:00
Mo Tarbin
1786a5e910 Merge branch 'dev' 2026-02-10 20:38:16 -05:00
Mo Tarbin
d9d93ffad3 clean up imports and remove unused quick schedule functionality in DateModal 2026-02-10 20:38:01 -05:00
Mo Tarbin
032b9f1f17 update version codes to 0.4.0 for Android, iOS, and package.json 2026-02-10 19:06:01 -05:00
Mo Tarbin
eba629e5a7 sync version across ios /android and web 2026-02-10 19:05:09 -05:00
Mo Tarbin
41fb8b6bf4 add bump-version script and update password reset functionality 2026-02-10 12:00:27 -05:00
Mo Tarbin
430e6025fa Merge branch 'dev' 2026-02-10 11:46:16 -05:00
Mo Tarbin
57a16c4904 add bump-version script and update password reset functionality 2026-02-10 11:46:06 -05:00
Mo Tarbin
4525aee9a1 Merge branch 'dev' 2026-02-10 11:11:02 -05:00
Mo Tarbin
e99aae3ed4 fix: hide NavBar on specific domain names 2026-02-10 11:10:50 -05:00
Mo Tarbin
a9cff1f49a Merge branch 'dev' 2026-02-10 01:15:45 -05:00
Mo Tarbin
f5b0f06bba show Ops, something went wrong
if we unable to load chore
2026-02-10 00:57:32 -05:00
Mo Tarbin
f65e72fdc1 Merge branch 'dev' 2026-02-10 00:44:12 -05:00
Mo Tarbin
979565691f adjust due date formatting to include the last second of the day 2026-02-10 00:43:59 -05:00
Mo Tarbin
9c115efecb fix: ensure apiClient initialization and update resource queries in authentication flow 2026-02-10 00:42:25 -05:00
Mo Tarbin
1ce7749826 better display Task has only due date without time 2026-02-10 00:41:08 -05:00
Mo Tarbin
ef232aba88 Merge branch 'dev' 2026-02-09 23:31:25 -05:00
Mo Tarbin
0c9619a550 fix: streamline public pages handling in NavBar component ( revert to previous state) 2026-02-09 23:31:18 -05:00
Mo Tarbin
8b9d20d908 Merge branch 'dev' 2026-02-09 23:25:34 -05:00
Mo Tarbin
1006254090 fix: update landing page routing based on domain conditions 2026-02-09 23:23:26 -05:00
Mo Tarbin
b784f94a64 implement deep link handling for OAuth authentication
https://github.com/donetick/donetick/issues/504
2026-02-09 23:23:12 -05:00
Mo Tarbin
34c382daea feat: add undo functionality for skipped tasks in chore actions 2026-02-09 23:20:10 -05:00
Mo Tarbin
1b57be1d64 Show ability to undo task on choreView
https://github.com/donetick/donetick/issues/505
2026-02-09 23:18:45 -05:00
Mo Tarbin
25676cff8c Limit Local notification to 64 https://github.com/donetick/donetick/issues/506 2026-02-09 23:14:59 -05:00
Mo Tarbin
476c9f5840 Fix Google Authentication sending [object object] instead of serialized obj 2026-02-09 11:16:22 -05:00
Mo Tarbin
d663f047bd Fix OAuth URL 2026-02-09 11:15:36 -05:00
Mo Tarbin
7663a53e1c Merge branch 'dev' 2026-02-08 21:56:17 -05:00
Mo Tarbin
117d8b99df fix: update request body handling in POST and PUT methods to accept raw data 2026-02-08 21:19:55 -05:00
Mo Tarbin
bec69b4706 Merge branch 'dev' 2026-02-08 16:33:49 -05:00
Mo Tarbin
0beb876cb4 refactor: update color and background properties in multiple views for consistency 2026-02-08 16:33:32 -05:00
Mo Tarbin
666eb75779 Merge branch 'dev' 2026-02-08 16:15:22 -05:00
Mo Tarbin
b31bcc2a9c remove the need to resource and profile data on landing page 2026-02-08 16:08:56 -05:00
Mo Tarbin
2c1458e026 chore: update VITE_IS_LANDING_DEFAULT variable to true in .env 2026-02-08 13:58:32 -05:00
Mo Tarbin
8d65b5117e chore: add VITE_IS_LANDING_DEFAULT variable to .env.development 2026-02-08 13:23:45 -05:00
Mo Tarbin
1e0c8a594f chore: update package-lock.json to version 0.1.145 and add new dependencies 2026-02-08 11:40:15 -05:00
Mo Tarbin
b05da7d27c refactor: update NavBar component to include additional public pages and separate AppNavBar and LandingNavBar logic 2026-02-08 11:38:14 -05:00
Mo Tarbin
00e6cf537a Merge branch 'dev' 2026-02-08 10:29:57 -05:00
Mo Tarbin
c2c1c6dfcc update authentication logic to conditionally include credentials for native platforms 2026-02-08 10:29:39 -05:00
Mo Tarbin
753d4cd981 Merge branch 'dev' 2026-02-08 01:40:47 -05:00
Mo Tarbin
86cfc10741 chore: update dependencies in package.json and refactor import statements in modal components 2026-02-08 01:40:33 -05:00
Mo Tarbin
492e2f2e7e refactor: update modal components to use larger size and full width with titles 2026-02-08 01:39:33 -05:00
Mo Tarbin
560cceca9b refactor: simplify menu icon logic in NavBar component 2026-02-08 01:35:45 -05:00
Mo Tarbin
f19f8ca2a7 Merge branch 'dev' 2026-02-07 23:31:04 -05:00
Mo Tarbin
925cf982ca chore: update version to 0.1.145 in package.json 2026-02-07 23:30:54 -05:00
Mo Tarbin
30a7e3b429 Merge branch 'main' of https://github.com/Donetick/frontend 2026-02-07 23:28:08 -05:00
Mo Tarbin
f978c6f7d7 enhance Fetch function to handle different HTTP methods in apiClient 2026-02-07 23:26:55 -05:00
Mo Tarbin
facbf8ec02 replace loading state with LoadingComponent in CircleSettings 2026-02-07 23:26:40 -05:00
Mo Tarbin
ac338e9299 fix: update link to redirect users to the Google Play Store 2026-02-07 23:26:25 -05:00
Mo Tarbin
d18e6412f0 feat: add quick scheduling options in DateModal with chips for today, tomorrow, weekend, and next week 2026-02-07 23:26:17 -05:00
Mo Tarbin
373096b339 Rewrite the Swiping Logic and update the Project, Labelm Things,Chore and all swipe card/view 2026-02-07 23:26:06 -05:00
Mohamad Tarbin
bb4bff50b3 Merge pull request #49 from hoborm/feature/swagger
Exclude swagger for service worker fallback
2026-02-06 18:12:55 -05:00
Mo Tarbin
c9baf04505 Refactor: update condition handling for status selection in AdvancedFilterBuilder
Fix https://github.com/donetick/frontend/issues/59
2026-02-05 10:36:49 -05:00
Mo Tarbin
938fec1ab3 Fix: prevent the layout jump when you start typing https://github.com/donetick/frontend/issues/58 2026-02-05 10:28:17 -05:00
Mo Tarbin
ed9f04332e remove color chip from Project and Label
https://github.com/donetick/frontend/issues/57
2026-02-05 09:23:14 -05:00
Mo Tarbin
c20e8d1aea Refactor: optimize filter sorting with useMemo and integrate useFilters in AdvancedFilterBuilder 2026-02-04 00:22:07 -05:00
Mo Tarbin
3a13f111eb reorganize filter query hooks and remove unused track usage mutation 2026-02-04 00:09:14 -05:00
Mo Tarbin
6c95c683ba migrate filter management to API and implement query hooks for filters 2026-02-04 00:06:44 -05:00
Mo Tarbin
d666f59c1b https://github.com/donetick/donetick/issues/493 2026-02-03 17:57:48 -05:00
Mo Tarbin
28869498ae add points condition evaluation and update filter builder for points selection 2026-02-03 00:46:10 -05:00
Mo Tarbin
81104a3f38 Refactor: simplify filter chip rendering and adjust styles for better usability 2026-02-03 00:45:52 -05:00
Mo Tarbin
48cdbf6b6b remove the icon and show only the color for now 2026-02-02 19:39:08 -05:00
Mo Tarbin
7e9ce00166 have the project id default to whatever select when open new task 2026-02-02 19:33:35 -05:00
Mo Tarbin
c3431b0921 Refactor: update placeholder text for filter name and replace label colors with project colors in ProjectModal 2026-02-02 19:32:25 -05:00
Mo Tarbin
27210317fd Fix: navigate to chores instead of filters via and provide searchparam 2026-01-31 13:06:05 -05:00
Mo Tarbin
312b51a5fd Hide the scroll back on the chip for quick filter 2026-01-31 12:54:45 -05:00
Mo Tarbin
96a649ca9c Scroll to the new condition when adding new field 2026-01-31 12:52:54 -05:00
Mo Tarbin
445d8168e1 if filter selected then remove the advance filter and vera versa 2026-01-31 12:49:26 -05:00
Mo Tarbin
24a219853e update default project description for clarity and remove the default color 2026-01-31 01:23:46 -05:00
Mihaly Hobor
4271159294 Merge branch 'main' into feature/swagger 2026-01-28 18:28:22 +01:00
Mo Tarbin
9ff94a4402 fix: remove unnecessary blank lines and correct syntax error in importFilters function 2026-01-28 00:00:25 -05:00
Mo Tarbin
448b8fa160 feat: enhance filter functionality and UI improvements
- Added FilterView component for managing custom filters.
- Implemented temporary filter application in MyChores and custom filter hooks.
- Improved sorting of archived chores by updated date.
- Enhanced SortAndGrouping component with keyboard navigation support.
- Updated CustomFilterChips to visually indicate active filters.
- Refactored AdvancedFilterBuilder to improve usability and added listbox positioning.
- Integrated project selection caching in ProjectView for better navigation.
- Cleaned up unused imports and optimized existing code for better performance.
2026-01-27 23:50:49 -05:00
Mo Tarbin
aa46eb4c6d fix: Update notification timing label and refactor notification rendering for improved clarity 2026-01-26 23:08:36 -05:00
Mo Tarbin
7e35fa8710 feat: Enhance FadeModal with title and footer support; update AdvancedFilterBuilder to use fullWidth 2026-01-26 23:08:28 -05:00
Mo Tarbin
66b9e9b5c1 fix: Ensure 'Content-Type' header is set for POST, PUT, and DELETE requests 2026-01-26 23:08:13 -05:00
Mo Tarbin
ad45bafd62 feat: Refactor Filter Section and Add Filter View
- Removed unused props and components from FilterSection.
- Introduced FilterView component to manage and display saved filters.
- Implemented swipe functionality for filter actions (edit, delete, pin).
- Enhanced AdvancedFilterBuilder with description and color selection.
- Deleted obsolete SaveFilterModal component.
- Updated NavBar to include a link to the new Filters page.
- Adjusted chore filter hooks for improved functionality and organization.
2026-01-26 17:27:27 -05:00
Mihály Hóbor
4cb2b34d11 Change comment 2026-01-26 16:32:53 +01:00
Mo Tarbin
2b8482cb06 feat: add custom filter chips and filter section components
- Implemented CustomFilterChips component for displaying and managing custom filters with context menu options for pinning, editing, and deleting filters.
- Created FilterSection component to integrate CustomFilterChips and provide UI for creating advanced filters and displaying active filters.
- Introduced useCustomFilters hook to manage custom filter logic, including loading, saving, updating, and deleting filters.
- Added AdvancedFilterBuilder modal for creating and editing advanced filters with dynamic condition handling.
- Implemented SaveFilterModal for saving filters with preview functionality and validation for filter names.
- Enhanced useChoreFilters and useProjectFilter hooks for improved filter management and state handling.
2026-01-26 01:58:21 -05:00
Mo Tarbin
57bc6ad98e Refactor MyChores component for improved maintainability
Reduced MyChores.jsx from 2,839 to 1,364 lines (52% reduction) by extracting reusable hooks and components.

   Created 6 custom hooks:
   - useMultiSelect: Multi-select mode and selection state management
   - useChoreModals: Centralized modal state management
   - useProjectFilter: Project filtering with localStorage sync
   - useChoreFilters: Multi-layer filtering (project, search, user filters)
   - useKeyboardShortcuts: All keyboard event handling
   - useChoreActions: Chore actions and bulk operations

   Created 3  components:
   - SearchBar: Clean search input with keyboard hints
   - MultiSelectToolbar: Full multi-select toolbar with action buttons
   - ChoreModals: Centralized modal rendering
2026-01-25 21:26:15 -05:00
Mohamad Tarbin
8ec8816e45 Merge pull request #27 from Tirzono/fix-notification-typo
fix: change Notificaiton to Notification
2026-01-25 19:59:27 -05:00
Mohamad Tarbin
801bc2ab66 Merge branch 'main' into fix-notification-typo 2026-01-25 19:58:31 -05:00
Mohamad Tarbin
5fec87e688 Merge pull request #43 from natea/main
fix: remove optional=false from .npmrc to fix esbuild installation
2026-01-25 19:52:53 -05:00
Mohamad Tarbin
9490c00f9f Merge pull request #36 from SlIdE42/patch-1
Fix missing HTML title
2026-01-25 19:35:05 -05:00
Mihály Hóbor
a14dde8183 Show chore assigned person even if it's our own. 2026-01-25 23:32:04 +01:00
Mohamad Tarbin
b742cda635 Merge pull request #47 from hoborm/feature/windows-developer-build
Add windows developer build
2026-01-22 22:50:54 -05:00
Mihaly Hobor
2e92acbfd5 Exclude swagger for service worker fallback 2026-01-22 23:17:02 +01:00
Mihaly Hobor
7af904d860 Add windows developer build 2026-01-22 23:15:16 +01:00
Mo Tarbin
59289a2f40 Merge branch 'dev' 2026-01-21 00:26:18 -05:00
Mo Tarbin
b08d0a76ee fix: Update import path for apiClient to use consistent casing 2026-01-21 00:26:12 -05:00
Mo Tarbin
cc8fdbe4a6 Merge branch 'dev' 2026-01-21 00:19:18 -05:00
Mo Tarbin
64eb477f4f fix: Correct import path formatting for apiClient 2026-01-21 00:19:08 -05:00
Mo Tarbin
68f368dc94 Merge branch 'dev' 2026-01-21 00:16:40 -05:00
Mo Tarbin
219d9b2a59 fix: Update import paths for apiClient to use consistent casing 2026-01-21 00:16:26 -05:00
Mo Tarbin
a7e1506ea0 Merge branch 'dev' 2026-01-21 00:12:55 -05:00
Mo Tarbin
f61cfaa781 fix: Update import path for apiClient to use consistent casing 2026-01-21 00:12:42 -05:00
Mo Tarbin
66de395549 Merge branch 'dev' 2026-01-21 00:09:44 -05:00
Mo Tarbin
242f382da3 chore: Remove empty optionalDependencies section from package.json 2026-01-21 00:09:38 -05:00
Mo Tarbin
a879bd09b4 feat: Add android build script and baseline-browser-mapping dependency 2026-01-21 00:09:15 -05:00
Mo Tarbin
ed273fbfce chore: Bump version to 0.1.120 in package.json 2026-01-21 00:08:08 -05:00
Mo Tarbin
31cb8f9fab Update import paths for apiClient to use consistent casing 2026-01-21 00:07:13 -05:00
Mo Tarbin
2aeb6598dc Merge branch 'dev' 2026-01-20 19:40:11 -05:00
Mo Tarbin
9810083304 fix: Correct import path for apiClient in useAuth hook 2026-01-20 19:40:00 -05:00
Mohamad Tarbin
23fd0482c8 Merge pull request #38 from pano9000/main
fix: UI strings - use consistent spacing/capitalization
2026-01-18 12:57:38 -05:00
Mohamad Tarbin
39f9e16a61 Merge pull request #39 from louim/bugfix/week-of-month
Replace nth_day_of_month with week_of_month
2026-01-18 12:56:58 -05:00
Mo Tarbin
c3a5e759b7 Merge branch 'dev' 2026-01-18 12:54:58 -05:00
Mo Tarbin
f9d5aeee91 feat: Add reconnection schedule and timeout configuration to Developer Settings 2026-01-18 12:54:49 -05:00
Mo Tarbin
371631856a feat: Add Developer Settings page and integrate with SSE context for debugging
refactor: Update ApiClient to support dynamic server URL and improve token handling
refactor: Modify TokenStorage to utilize Capacitor for native platforms
refactor: Adjust Fetcher to use updated ApiClient methods
refactor: Enhance SettingsOverview to include Developer Settings option
2026-01-18 12:54:13 -05:00
Mohamad Tarbin
73f33bc0a3 Merge pull request #44 from ricmatsui/feature/avoid-tab-search-conflict
Ignore Cmd/Ctrl+Shift+A to avoid conflict with Chrome tab search shortcut
2026-01-17 19:37:59 -05:00
Mohamad Tarbin
ed595a3815 Merge pull request #37 from lauraneto/bugfix/android-allow-http-requests
Allow HTTP (non secure) requests in Android app
2026-01-17 19:37:01 -05:00
Mo Tarbin
7c8fa27aaf feat: Add unarchive functionality to ChoreView and enhance project management features
- Implemented unarchive button for archived chores in ChoreView.
- Updated chore status handling to disable actions for archived chores.
- Enhanced MyChores component to filter tasks based on project selection, including a default project.
- Improved ProjectModal to streamline project creation and editing with a new footer layout.
- Refactored ProjectView to accurately count tasks for default and user projects.
- Added project selection dropdown in AddTaskModal with default project handling.
- Updated NavBar to handle logout using apiClient.
- Enhanced ProjectSelector to manage projects with a new menu item for project management.
2026-01-17 19:35:36 -05:00
Mo Tarbin
b326b1b3d7 refactor: update localStorage keys for token and expiration in authentication components 2026-01-16 15:04:27 -05:00
Mo Tarbin
f527064e55 implement View Transitions API for smoother page navigation and replace the current implementation 2026-01-16 12:12:36 -05:00
Mo Tarbin
3a074ef6c5 Add Support Project 2026-01-16 12:12:00 -05:00
Mo Tarbin
7fbae16a53 Add Support Project 2026-01-16 12:11:03 -05:00
Mo Tarbin
98018ca590 fix: update SSE message handler to reflect latest userProfile changes
there was issue where userprofile was undefined cause the message being display for same user how make the action.  The new useEffect hook updates the EventSource's handler whenever handleSSEMessage changes
2026-01-10 14:14:45 -05:00
Mo Tarbin
7d5724d8d5 add project filtering to MyChores component 2026-01-01 02:14:19 -05:00
Mo Tarbin
ba17a5592c feat: add ProjectModal component for creating and editing projects 2026-01-01 01:32:23 -05:00
Mo Tarbin
7332e81e6e Fix https://github.com/donetick/donetick/issues/373 compact card not showing the right performer 2025-12-27 16:45:49 -05:00
Mo Tarbin
5aeacef511 fix: enhance SSE error handling and token refresh logic; improve user profile checks in MyChores component 2025-12-26 19:59:39 -05:00
Ricardo Matsui
8f3fd3b37e Ignore cmd/ctrl+shift+a to avoid conflict with Chrome tab search shortcut 2025-12-26 12:42:12 -08:00
Mo Tarbin
0fd58860a8 Improve the flow for archive screen. Fix https://github.com/donetick/frontend/issues/41 2025-12-25 22:55:09 -05:00
Mo Tarbin
8edd3774d2 Support Refresh token and improve authentication and security.
Refactor authentication handling and API client integration

- Updated UserProfileAvatar to use 'access_token' instead of 'ca_token' for logout.
- Removed SSEProvider from Contexts and adjusted related imports.
- Introduced useAuth hook for centralized authentication logic, including login, logout, and token management.
- Refactored useSSE to utilize the new useAuth hook for token validation.
- Updated UserQueries to check for token validity using the new method.
- Deleted AuthenticationService as its functionality is now handled by useAuth.
- Created a new ApiClient utility for handling API requests and token management.
- Updated various components and views to use the new ApiClient for API interactions.
- Removed TokenManager and migrated its functionality to the new ApiClient.
- Adjusted LoginView and related components to utilize the new authentication flow.
- Cleaned up unused variables and improved code consistency across components.
2025-12-25 22:54:39 -05:00
Nate Aune
dd1a4cba76 fix: remove optional=false from .npmrc to fix esbuild installation
Problem:
npm install was failing with the error:
  Error: Expected "0.21.5" but got "0.18.20"

This occurred because esbuild's install.js validates that the installed
binary version matches the package.json version, but was finding an
older cached binary.

Root cause:
The .npmrc setting `optional=false` was preventing esbuild from
downloading its platform-specific binary package (@esbuild/darwin-arm64,
etc.). These platform binaries are marked as optionalDependencies in
esbuild's package.json.

Without the correct platform binary, esbuild's postinstall script would
find a stale/cached binary from a previous installation and fail the
version check.

Troubleshooting steps taken:
1. Attempted rm -rf node_modules && npm install - same error
2. Cleared npm cache with npm cache clean --force - same error
3. Checked for global esbuild installations - none found
4. Reviewed npm config and found optional=false in .npmrc
5. Ran npm install --include=optional - succeeded
6. Removed optional=false from .npmrc to permanently fix

The fund=false and audit=false settings are retained as they don't
affect dependency installation, only npm's output behavior.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 11:24:19 -05:00
Mo Tarbin
1123fb3ca6 fix: update onAction handler to accept extra data in ChoreCard component 2025-12-02 18:42:16 -05:00
Mo Tarbin
5bfd340176 Support unicode letter in the parser. Fix https://github.com/donetick/donetick/issues/395 2025-12-02 15:58:06 -05:00
Mo Tarbin
7cb2f203b1 refine platform check for native functionality in AccountSettings and Settings components 2025-12-02 00:23:13 -05:00
Louis-Michel Couture
412d0a19e7 Replace nth_day_of_month with week_of_month
The backend expects this string since 0fa913fb83
2025-10-31 00:18:04 -04:00
Panagiotis Papadopoulos
f2a50141b7 fix: UI strings - use consistent spacing/capitalization 2025-10-29 08:37:23 +01:00
Laura Neto
7f65ce0e84 Allow HTTP (non secure) requests in Android app 2025-10-19 19:22:30 +02:00
SlIdE42
8f577a4368 Fix #33 2025-10-07 19:31:07 +02:00
Mo Tarbin
09f89afe2a fix: update state initialization and improve Grid component usage in ChoreView 2025-10-05 14:24:26 -04:00
Mo Tarbin
d1dcdc2f50 feat: add 'Gentle Nudges' feature with customizable reminders in FeaturesSection 2025-10-05 14:16:25 -04:00
Mo Tarbin
e31a5f705c replace CalendarView with CalendarMonthly and improve chore date formatting 2025-10-04 13:18:25 -04:00
Mo Tarbin
04314d507b Fix: https://github.com/donetick/donetick/issues/127
https://github.com/donetick/donetick/issues/277
2025-10-03 00:42:33 -04:00
Mo Tarbin
409c5a0ba3 enhance user input validation and parsing for usernames, points, and labels 2025-10-02 21:45:25 -04:00
Mo Tarbin
68f09125d4 chore: bump version to 0.1.115 2025-09-28 19:32:40 -04:00
Mo Tarbin
ac2d4911fe feat: update user activity filters to allow selection of last 7 days and improve UI layout 2025-09-28 19:13:38 -04:00
Mo Tarbin
26c2eaddff implement child user management functions and user type utilities 2025-09-28 19:13:28 -04:00
Mo Tarbin
d41d6bd758 feat: add sub user management features including creation, deletion, and password updates 2025-09-28 19:12:26 -04:00
Mo Tarbin
86b8bbfb5f show API version on navbar 2025-09-28 18:46:56 -04:00
Mo Tarbin
7658b4c9fe feat: add 'Anyone' option for assignees and disable Limited option when no assignees are selected 2025-09-28 02:46:15 -04:00
Mo Tarbin
f1384eef34 enhance chore management with status updates and default assignee settings 2025-09-28 02:24:08 -04:00
Mo Tarbin
c7c4a011ef Refactor chore management components to centralize action handling
- Removed individual chore action handlers from ChoreCard and CompactChoreCard.
- Introduced a unified `onAction` prop to handle various chore actions (approve, reject, complete, start, pause, delete, etc.) in a centralized manner.
- Updated ChoreActionMenu to utilize the new `onAction` prop for performing actions on chores.
- Simplified state management and notification handling for chore updates.
- Cleaned up unused imports and state variables across affected components.
2025-09-28 02:20:18 -04:00
Mo Tarbin
bdd73135f0 feat: integrate impersonated user handling for task completion 2025-09-27 20:29:28 -04:00
Mo Tarbin
b367410aaf fix: adjust transition timeout and add UNASSIGNED color constant 2025-09-27 13:48:20 -04:00
Mo Tarbin
c27404cc3a Refactor chore management modals and actions for centralized handling
- Removed individual modal states and handlers from ChoreCard and CompactChoreCard components.
- Introduced a centralized modal state and handler in MyChores component to manage modals for changing due dates, completing with past dates, changing assignees, adding notes, writing NFC, and nudging.
- Updated action handlers to utilize the new centralized approach for better maintainability and readability.
- Cleaned up unused imports and code related to modal management in ChoreCard and CompactChoreCard components.
2025-09-27 13:47:41 -04:00
Mo Tarbin
9ff2359b4c Remove Websocket code since we are only using SSE 2025-09-27 13:38:45 -04:00
Mohamad Tarbin
d28ecb509e Performance optimization 09 24 (#6)
* perf: optimize MyChores component performance and fix timer errors

## Fixed Issues
-  Timer error: `Timer '🏁 Main useEffect processing' does not exist`
-  Reduced 1049ms and 613ms message handler violations
-  Fixed 1+ second blank screen before chores display
-  Eliminated multiple redundant `getFilteredChores` calculations

## Performance Optimizations

### 1. Fixed Timer Execution Issue
**Problem**: React strict mode was causing timer mismatch between `console.time` and `console.timeEnd`
**Solution**: Restructured async useEffect to ensure proper timer lifecycle
```javascript
// Before: Timer in async IIFE caused double-execution issues
;(async () => {
  console.time('🏁 Main useEffect processing')
  // ...
  console.timeEnd('🏁 Main useEffect processing')
})()

// After: Proper async function structure
const processEffectAsync = async () => {
  // ... async operations
  console.timeEnd('🏁 Main useEffect processing')
}
processEffectAsync()
```

### 2. Optimized useState Lazy Initialization
**Problem**: `JSON.parse()` called on every render for state initialization
```javascript
// Before: Expensive operation on each render
const [openChoreSections, setOpenChoreSections] = useState(
  JSON.parse(localStorage.getItem('openChoreSections')) || {},
)

// After: Lazy initialization with error handling
const [openChoreSections, setOpenChoreSections] = useState(() => {
  try {
    return JSON.parse(localStorage.getItem('openChoreSections')) || {}
  } catch {
    return {}
  }
})
```

### 3. Reduced useEffect Dependencies
**Problem**: useEffect running too frequently due to object reference dependencies
```javascript
// Before: Full objects cause frequent re-runs
}, [choresData, membersData, userProfile, impersonatedUser, ...]

// After: Only specific properties that matter
}, [choresData?.res, membersData?.res, userProfile?.id, impersonatedUser?.userId, ...]
```

### 4. Added Memoization for Section Updates
**Problem**: `choreSections` updated even when data hadn't actually changed
```javascript
// Before: Always updating sections
setChoreSections(processedSections)

// After: Only update if data actually changed
setChoreSections(prevSections => {
  if (JSON.stringify(prevSections) === JSON.stringify(processedSections)) {
    return prevSections
  }
  return processedSections
})
```

### 5. Optimized localStorage Access
**Problem**: Multiple `localStorage.getItem()` calls and repeated parsing
```javascript
// Before: Multiple localStorage calls
if (localStorage.getItem('openChoreSections') === null) {
  // ...localStorage operations
}

// After: Single cached read
const storedSections = localStorage.getItem('openChoreSections')
if (storedSections === null) {
  // ...operations
}
```

### 6. Added useMemo/useCallback for Heavy Computations
- `processedChores` - Memoized chore sorting and filtering
- `processedSections` - Memoized section grouping
- `getFilteredChores` - Memoized filtered chore calculations
- `handleChoreUpdated`, `handleChoreDeleted`, `updateChores` - useCallback for stable references

## Performance Results
**Before**: 1+ second loading delay, timer errors, frequent violations
**After**:
- `processedChores calculation: ~0.002ms` (was much slower)
- `processedSections calculation: ~0.001ms` (was much slower)
- `getFilteredChores: ~0.022ms` (down from multiple slow calls)
- `Main useEffect processing: ~0.298ms` (reasonable time)
- `Auto-update sections: ~0.007ms` (very fast)

🚀 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* chore: update package.json to remove deprecated @vitejs/plugin-react dependency and add wrangler.toml for build configuration

* Revert vite.config.js to it's original state

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-26 02:21:07 -04:00
Mo Tarbin
048e7d0ef6 Merge branch 'dev' of https://github.com/Donetick/frontend into dev 2025-09-24 02:19:33 -04:00
Mo Tarbin
1b49a6f3f7 feat: add @vitejs/plugin-react dependency for improved React support 2025-09-21 16:52:53 -04:00
Mo Tarbin
fd6e4880d2 refactor: remove unused safe area utility and simplify layout structure 2025-09-21 13:04:30 -04:00
Mo Tarbin
f27bbd318f Refactor chore management to use React Query hooks for timer and chore actions
- Replaced direct API calls with React Query hooks in ChoreView, ChoreCard, CompactChoreCard, and TimerDetails components for better state management and error handling.
- Updated ArchivedTasks to utilize useUnArchiveChore hook for restoring archived chores.
- Enhanced NotificationSetting to include device registration logic and improved user feedback for push notifications.
- Refactored TimerEditModal and TimerDetails to streamline timer session updates and deletions using hooks.
- Improved ChoreActionMenu to handle archiving and unarchiving chores with hooks.
- Adjusted various components to use getSafeBottomStyles for consistent bottom padding.
- Cleaned up unused imports and optimized loading states across components.
2025-09-21 12:46:03 -04:00
Mo Tarbin
79dfb11fa4 feat: add device token management and safe area utilities; enhance notification settings and chore components 2025-09-20 22:20:02 -04:00
Mo Tarbin
3bf9126595 refactor: replace NotificationSettings component with NotificationSetting in RouterContext 2025-09-20 19:07:26 -04:00
Mo Tarbin
a5a90dfbdd refactor NotificationSetting component to use SettingsLayout; remove NotificationSettings wrapper 2025-09-20 18:45:40 -04:00
Mo Tarbin
ac767f63ae Fix: pass the right user id when impersonating a user to chorefilter
implement experimental offline mode; add toggle in StorageSettings and update chore filters
2025-09-20 18:15:52 -04:00
Mo Tarbin
782862294d feat: integrate Firebase Messaging for push notifications; update AppDelegate and add Info.plist for widget support 2025-09-20 17:32:50 -04:00
Mo Tarbin
eded4b2e16 feat: add nudge functionality to chore cards and action menu; enhance user notifications
fix Filtering when imposing user to respect the sort and grouping order
2025-09-18 01:14:51 -04:00
Mo Tarbin
707ba55e1d feat: implement push notification registration and nudge feature; enhance user settings and notification handling 2025-09-18 01:13:37 -04:00
Mo Tarbin
b71a533024 enhance impersonation context and user profile handling; improve UI interactions in chore history and timer details 2025-09-15 23:52:28 -04:00
Mo Tarbin
36093b9199 refactor: update hero text in HomeHero component for clarity and engagement 2025-09-14 22:05:51 -04:00
Mo Tarbin
bd14a35e23 add terms and privacy policy agreement message to SignupView 2025-09-14 21:56:53 -04:00
Mo Tarbin
406da9732c Fix broken access to term and privacy pages 2025-09-14 21:55:14 -04:00
Mo Tarbin
219aa06835 chore: bump version to 0.1.111 2025-09-11 01:18:39 -04:00
Mo Tarbin
43decb21f4 Refactor StorageSettings to use SettingsLayout and improve layout structure; add ThemeSettings component; update TermsView with new terms and structure; enhance ThingsView styling; clean up AddTaskModal by removing experimental feature chip; create CalendarCard component for calendar overview; optimize CustomParsers for repeat parsing; update NavBar for improved navigation and search parameter handling. 2025-09-11 01:17:27 -04:00
Mo Tarbin
b152da9d21 feat: add ipad screenshot asset and update TabletInstallationSection to use it 2025-09-04 09:16:32 -04:00
Mo Tarbin
14ce2305ce refactor: remove open source badge from footer 2025-09-04 03:01:42 -04:00
Mo Tarbin
a65cb92f37 feat: update TabletInstallationSection to use imported image asset 2025-09-04 02:59:50 -04:00
Mo Tarbin
4a54115e31 remove option dependency 2025-09-04 02:49:30 -04:00
Mo Tarbin
3a80838b4c chore: remove architecture-specific dependencies for darwin arm64 2025-09-04 02:43:24 -04:00
Mo Tarbin
bb16da0f4a feat: add TabletInstallationSection component with responsive design and features 2025-09-04 02:41:54 -04:00
Mo Tarbin
714ae7b9f0 chore: add rollup and swc core dependencies for darwin arm64 architecture 2025-09-04 02:40:27 -04:00
Mo Tarbin
f5f60cc9eb Update dependencies and move architecture-specific packages to optionalDependencies 2025-09-04 02:27:50 -04:00
Mo Tarbin
057c5f7ec8 feat: Add notification types and enhance color management
- Introduced NOTIFICATION_TYPE constants for pre-due, due date, and post-due notifications in Colors.jsx.
- Updated HistoryCard.jsx to utilize TASK_COLOR for chip colors based on task status.
- Created DemoCalendar.jsx to showcase a visual task calendar with sample chore data.
- Enhanced DemoMyChore.jsx to include status for demo tasks.
- Added DemoNotificationTemplate.jsx for demonstrating smart notification scheduling.
- Revamped FeaturesSection.jsx to reflect updated feature descriptions and icons.
- Updated Footer.jsx to link to the correct API reference documentation.
- Improved GettingStarted.jsx with new mobile app download options and enhanced layout.
- Integrated TabletInstallationSection into Landing.jsx for better user guidance.
2025-09-04 01:49:19 -04:00
Mo Tarbin
d704588624 Update Feature Section 2025-09-03 22:56:12 -04:00
Mo Tarbin
c82a6cc0e1 feat: Add Discord and Reddit icon components 2025-09-02 22:41:21 -04:00
Mo Tarbin
603d83ba1b Revamp Footer component with enhanced layout, social links, and updated styling 2025-09-02 22:40:28 -04:00
Mo Tarbin
fd15235124 Enhance UI with section headers and descriptions for Archived Tasks, Labels, Settings, Things, User Activities, and update NavBar 2025-09-02 17:39:05 -04:00
Mo Tarbin
0c1e5a9628 chore: Bump version to 0.1.110 2025-09-02 01:50:49 -04:00
Mo Tarbin
6403d135ea feat: Implement User Switcher and add subscription cancellation modal 2025-09-02 01:50:06 -04:00
Mo Tarbin
a7b33c48b3 fix: Update navigation path after saving chore to remove trailing slash 2025-09-01 23:58:14 -04:00
Mo Tarbin
4e31190291 Add Capacitor Browser dependency and update safe area handling in components 2025-08-30 01:35:38 -04:00
Mo Tarbin
e99a06654e chore: Bump version to 0.1.109 and update dependencies 2025-08-29 00:54:27 -04:00
Mo Tarbin
cf4d0565c5 feat: Enhance Signup and Chores functionality
- Added query invalidation on signup to refresh user profile data.
- Improved MyChores component to ensure data is loaded before rendering.
- Introduced dynamic sidepanel configuration with drag-and-drop functionality.
- Created TasksByAssigneeCard to visualize tasks assigned to users.
- Updated MFASettings and Settings components for better structure and usability.
- Implemented SettingsOverview for a comprehensive settings navigation experience.
- Added SidepanelSettings for customizing sidepanel card visibility and order.
- Refactored NavBar to include user profile avatar and improved layout.
2025-08-29 00:50:54 -04:00
Mo Tarbin
6b5a874db5 Refactor ChoreCard to remove unused circle members data and update approval logic to use performers 2025-08-26 22:11:10 -04:00
Mo Tarbin
defc7a8fa4 Remove unused icon import and comment out 'Upgrade to Plus' ListItemButton in NavBar 2025-08-25 23:58:49 -04:00
Mo Tarbin
06d568e61d Bump version to 0.1.108 in package.json 2025-08-25 23:41:56 -04:00
Mo Tarbin
6064c88f2c Refactor navigation paths to use '/chores' instead of '/my/chores' across multiple components for consistency 2025-08-25 20:21:06 -04:00
Mo Tarbin
77b3430339 Adjust BottomSheetModal minHeight and add margin to toggle button; add 'Upgrade to Plus' option in NavBar 2025-08-23 17:17:02 -04:00
Mo Tarbin
0f125cd63f Enhance modal components with consistent button sizes and improve calendar styles for better responsiveness and layout 2025-08-23 17:15:18 -04:00
Mo Tarbin
65f84b116f Refactor chore components and enhance scheduling features
- Removed redundant priority color function from CompactChoreCard and imported from Colors utility.
- Replaced FadeModal with ResponsiveModal in MultiSelectHelp for improved modal handling.
- Simplified MyChores component by removing archived chores state and related logic, and added keyboard shortcut for navigating to archived tasks.
- Integrated ResponsiveModal in RedeemPointsModal for consistent modal usage.
- Added quick scheduling options in ChoreActionMenu for better task management, including scheduling for today, tomorrow, weekend, and next week.
- Enhanced CustomParsers to support nth occurrence of days in monthly scheduling.
- Updated NavBar links and navigation logic for improved user experience.
2025-08-22 23:37:30 -04:00
Mo Tarbin
2d008a5cc3 Refactor EditThingStateModal to use ResponsiveModal for improved consistency 2025-08-21 01:39:25 -04:00
Mo Tarbin
4dcd4483e9 Refactor modals to use ResponsiveModal for improved responsiveness and consistency 2025-08-21 01:39:03 -04:00
Mo Tarbin
0102ce2144 Add BottomSheetModal component and implement calendar view in MyChores 2025-08-21 00:34:00 -04:00
Mo Tarbin
71d5887bcc Refactor calendar components: implement responsive design, enhance layout, and integrate monthly view with chore prioritization 2025-08-20 18:17:12 -04:00
Mo Tarbin
76ce301d91 Add success notification for task unplanned event in MyChores component 2025-08-19 01:11:44 -04:00
Mo Tarbin
692ccd7838 Add ApproveChore and RejectChore functions; update ActivityItem to handle Pending Approval and Rejected statuses 2025-08-17 22:28:44 -04:00
Mo Tarbin
bf97b1c115 Refactor Chores module: enhance grouping logic to include Pending Approval status and improve status categorization 2025-08-17 22:28:23 -04:00
Mo Tarbin
6eda3c68a8 Refactor chore management features to support approval and rejection workflows
- Updated RepeatSection to use occurrences instead of dayOccurrences for scheduling.
- Enhanced ChoreCard and CompactChoreCard to include approve/reject functionality for pending chores.
- Implemented user role checks for approval/rejection capabilities.
- Improved UI elements to reflect pending approval states with appropriate icons.
- Modified ChoreHistory and ThingsHistory components for better data representation and layout.
- Cleaned up unused imports and commented-out code for better readability.
2025-08-17 22:27:58 -04:00
Mo Tarbin
ca9a53bde9 CalendarView component: add priority color to show in the calendar cell, legend display to show two columns instead of one 2025-08-17 22:26:04 -04:00
Mo Tarbin
9b9327c25e Refactor ChoreEdit component: improve section toggle styling and remove unnecessary padding 2025-08-16 01:54:56 -04:00
Mo Tarbin
a2be4c73a1 Test Adding collapsible sections to ChoreEdit component for better organization and navigation 2025-08-16 01:42:17 -04:00
Mo Tarbin
720987197d Refactor ChoreEdit component: reorganize sections, enhance UI elements, and improve task assignment features 2025-08-16 01:41:54 -04:00
Mo Tarbin
c52e83fe10 Enhance ChoreEdit component with approval and visibility options 2025-08-16 01:20:18 -04:00
Mo Tarbin
e97e03b814 Refactor: reorder imports and clean up whitespace in PageTransition component 2025-08-11 17:01:27 -04:00
Mo Tarbin
ac9b85e10b enhance repeat section with week patterns and day occurrence options 2025-08-09 22:34:21 -04:00
Mo Tarbin
8e80af657f Merge branch 'main' into dev 2025-08-09 22:25:23 -04:00
Mo Tarbin
93f9afd98d Fix: use optional chaining for notificationMetadata properties 2025-08-09 00:14:06 -04:00
Mo Tarbin
c9178db87d Enhance Settings, Things History, User Activities, and User Points views
- Integrated RevenueCat for subscription management in Settings.
- Added subscription and user deletion modals in Settings.
- Improved analytics display in Things History with update frequency and trend calculations.
- Enhanced User Activities timeline with a more structured layout.
- Revamped User Points section with a leaderboard and detailed points analytics.
- Introduced responsive design elements and improved user experience across various components.
- Add permission for Camera to support uploading photo via camera
2025-08-04 22:25:30 -04:00
Mo Tarbin
18743f66e8 Merge branch 'dev' 2025-07-29 00:07:15 -04:00
Mo Tarbin
72ae2ec5c4 chore: bump version to 0.1.107 in package.json 2025-07-28 23:57:40 -04:00
Mo Tarbin
0a407d869e Fix: include notificationMetadata in chore creation when dueDate is set
Fix: https://github.com/donetick/donetick/issues/273
https://github.com/donetick/donetick/issues/272
2025-07-28 23:57:06 -04:00
Mo Tarbin
8c8b684cb4 initialize subTasks state with an empty array if not provided in response 2025-07-28 23:36:17 -04:00
Mo Tarbin
63d1b86b5e Merge branch 'dev' 2025-07-20 10:41:42 -04:00
Mo Tarbin
49a9055a73 chore: bump version to 0.1.106 in package.json 2025-07-20 10:41:28 -04:00
Mo Tarbin
4f444bd3c9 Feature: implement useThingHistory hook and refactor ThingsHistory component for improved data fetching and rendering 2025-07-20 10:41:14 -04:00
Mo Tarbin
1efab98f91 Merge branch 'dev' 2025-07-19 01:18:31 -04:00
Mo Tarbin
b8677b4c02 Fix: update FadeModal to use named import for Z_INDEX and remove redundant zIndex property( it was hiding select input when create label) 2025-07-19 01:18:21 -04:00
Mo Tarbin
e6400d8305 Merge branch 'dev' 2025-07-19 00:55:56 -04:00
Mo Tarbin
7bdfdcc1f8 Fix: text highlighting in SmartTaskTitleInput to support recurring events 2025-07-19 00:49:09 -04:00
Mo Tarbin
9d9c12a52d Merge branch 'dev' 2025-07-15 07:58:16 -04:00
Mo Tarbin
1aa9da57aa Update NavBar drawer content positioning for improved layout 2025-07-15 07:58:04 -04:00
Mo Tarbin
0b57e42652 Merge branch 'dev' 2025-07-14 02:05:52 -04:00
Mo Tarbin
9a988e82c4 Refactor z-index management by introducing Z_INDEX constants and updating components to use them for consistent layering 2025-07-14 00:53:56 -04:00
Mo Tarbin
9e83448cd0 Fix Duedate not being populated.
showing the user names on choreEdit
2025-07-13 14:00:06 -04:00
Mo Tarbin
8d9a3cbb1e Merge branch 'dev' 2025-07-13 01:32:57 -04:00
Mo Tarbin
fc5a40ace0 bump version to 0.1.105 2025-07-13 01:32:48 -04:00
Mo Tarbin
9f2d0b5b07 Merge branch 'dev' 2025-07-13 01:30:38 -04:00
Mo Tarbin
7e98e98ad0 update NetworkBanner positioning and zIndex for improved visibility 2025-07-13 01:30:24 -04:00
Mo Tarbin
f6085aa89b Merge branch 'dev' 2025-07-13 00:50:48 -04:00
Mo Tarbin
32905aa16b Merge branch 'page-motion' into dev 2025-07-13 00:50:22 -04:00
Mo Tarbin
8a240d506b Merge branch 'dev' 2025-07-13 00:35:22 -04:00
Mo Tarbin
b6f07fdf85 adjust NavBar positioning for improved layout and responsiveness 2025-07-13 00:26:53 -04:00
Mo Tarbin
9a7ab172ac style: update color properties in TimerDetails component for consistency 2025-07-12 19:24:49 -04:00
Mo Tarbin
3d6c70629d only show notification about event from other users 2025-07-12 19:23:34 -04:00
Mo Tarbin
c8d13a6fa1 Merge branch 'dev' 2025-07-12 16:37:04 -04:00
Mo Tarbin
b24ac01493 style: adjust padding-top in NavBar component for improved layout 2025-07-12 16:36:53 -04:00
Mo Tarbin
be21da5e3b implement custom useTimer hook for improved timer functionality 2025-07-12 16:36:41 -04:00
Mo Tarbin
b6fea7dc9b Merge branch 'dev' 2025-07-12 02:43:16 -04:00
Mo Tarbin
adc2e96bf2 refactor: clean up whitespace and improve comments in StatusBarManager 2025-07-12 02:43:07 -04:00
Mo Tarbin
807dc612a7 Merge branch 'dev' 2025-07-12 02:19:46 -04:00
Mo Tarbin
1612de8231 style: update NavBar component with improved padding and sticky positioning 2025-07-12 02:19:39 -04:00
Mo Tarbin
4576ddf09c Merge branch 'dev' 2025-07-12 00:41:31 -04:00
Mo Tarbin
bb96de47be refactor: remove redundant comment in getIdFromTemplate function 2025-07-12 00:38:30 -04:00
Mo Tarbin
ccfc56e629 fix: notification ID generation and clean up scheduleChoreNotification function 2025-07-12 00:36:45 -04:00
Mo Tarbin
e6cde49247 feat: Add KeyboardShortcutHint component for displaying keyboard shortcuts on non-mobile devices 2025-07-11 20:37:41 -04:00
Mo Tarbin
1de41a8d24 feat: Implement swipe functionality for CompactChoreCard with action buttons for start, pause, edit, and delete 2025-07-11 20:11:42 -04:00
Mo Tarbin
953c62cc66 feat: Enhance UserPoints component with improved filtering and layout
- Updated UserPoints component to include a more user-friendly filter bar with enhanced styling.
- Added a summary section to display the current filter context.
- Refactored user selection and time period filtering logic for better clarity and performance.
- Improved the layout of points cards and history sections for better visual hierarchy.
- Integrated a bar chart for visual representation of points over time.
- Updated redeem points functionality with better user feedback.

feat: Add keyboard shortcuts in AddTaskModal for improved usability

- Implemented keyboard shortcuts for adding descriptions, subtasks, and due dates.
- Enhanced user experience by providing visual hints for keyboard shortcuts.
- Refactored task creation logic to streamline the process.

fix: Refactor ChoreActionMenu to handle mouse events and improve accessibility

- Added mouse enter and leave event handlers for better interaction feedback.
- Adjusted menu positioning for improved usability.

refactor: Update RichTextEditor to support focus handling from parent components

- Converted RichTextEditor to use forwardRef for better integration with parent components.
- Exposed focus and blur methods for external control.
- Improved image upload handling with better error management.

fix: Adjust SubTask component to handle Enter key behavior correctly

- Modified key event handling to prevent unintended task creation when holding meta or ctrl keys.
- Added autoFocus prop to new task input for better user experience.
2025-07-11 20:10:28 -04:00
Mo Tarbin
c2f5569010 feat: add TimerEditModal component for managing timer sessions with real-time updates and editing capabilities 2025-07-09 21:23:34 -04:00
Mo Tarbin
baef35d263 refactor: update App component to use QueryClient and improve theme handling; enhance ChoreView and SubTask components with performers data 2025-07-09 21:02:55 -04:00
Mo Tarbin
8b8345d0e6 Refactor modals to use FadeModal component for consistent styling and improved user experience
- fix https://github.com/donetick/donetick/issues/222

- Replaced Modal and ModalDialog with FadeModal in LabelModal, PasswordChangeModal, SelectModal, TextModal, UserModal, WriteNFCModal, RedeemPointsModal, and AddTaskModal.
- Updated modal structure and layout to maintain functionality while enhancing visual consistency.
- Removed unused imports and commented-out code for cleaner codebase.
2025-06-27 01:42:38 -04:00
Mo Tarbin
3bab677607 Merge branch 'dev' 2025-06-23 01:55:38 -04:00
Mo Tarbin
79362162d2 refactor CookiePermissionSnackbar to use Snackbar directly and remove notification provider 2025-06-23 01:55:32 -04:00
Mo Tarbin
ca537c6321 Merge branch 'dev' 2025-06-23 01:47:51 -04:00
Mo Tarbin
79382ce6f8 fix: update build-selfhosted script to include package-lock.json cleanup and dependency installation 2025-06-23 01:47:45 -04:00
Mo Tarbin
ea70aa21a9 Merge branch 'dev' 2025-06-23 01:15:42 -04:00
Mo Tarbin
e9f1b2a9b4 fix: refactor getDefaultNotification to retrieve from localStorage and update notificationMetadata initialization 2025-06-23 00:54:05 -04:00
Mo Tarbin
981513086b fix: update version to 0.1.104 in package.json 2025-06-23 00:50:14 -04:00
Mo Tarbin
9f4bfe75d1 fix: remove rollup from dependencies and optionalDependencies in package.json 2025-06-22 22:08:33 -04:00
Mo Tarbin
dcd8bbbd01 fix: update build-cf script to remove unnecessary node_modules cleanup 2025-06-22 22:04:09 -04:00
Mo Tarbin
cadfa5e034 fix: update build commands and add optional dependencies for cross-platform support 2025-06-22 22:00:40 -04:00
Mo Tarbin
76ea0c4978 fix: update package.json and package-lock.json to include optional rollup and swc dependencies for darwin arm64 2025-06-22 21:51:20 -04:00
Mo Tarbin
c1321203c1 fix: update rollup and swc dependencies for darwin arm64 support 2025-06-22 21:45:33 -04:00
Mo Tarbin
a8388db1c3 add rollup as a dependency in package.json 2025-06-22 17:30:55 -04:00
Mo Tarbin
f0589c2f33 chore: remove unnecessary rollup dependency for darwin arm64 2025-06-22 17:28:20 -04:00
Mo Tarbin
fbe7d64d5d Merge branch 'dev' 2025-06-22 17:24:42 -04:00
Mo Tarbin
a5722b2445 refactor: simplify notification titles in ThingsView component 2025-06-22 17:24:10 -04:00
Mo Tarbin
18e57e20ed update dependencies to include rollup for darwin arm64 and swc core 2025-06-22 17:22:32 -04:00
Mo Tarbin
5b83bf35d0 update notification handling and improve sorting logic in NotificationTemplate component 2025-06-22 17:21:22 -04:00
Mo Tarbin
97fb8d8561 chore: update package.json to specify Node and npm engine requirements, and add build-cf script for clean build 2025-06-21 01:24:14 -04:00
Mo Tarbin
fe5a72ae90 Merge branch 'dev' 2025-06-21 01:19:56 -04:00
Mo Tarbin
643a48afec Update package lock 2025-06-21 01:19:40 -04:00
Mo Tarbin
e50598dfa3 Merge branch 'dev' 2025-06-21 01:12:57 -04:00
Mo Tarbin
46fb1f0ac0 chore: Bump version to 0.1.103 in package.json 2025-06-21 01:10:46 -04:00
Mo Tarbin
eaaeee6ee7 Merge branch 'dev' 2025-06-21 00:38:14 -04:00
Mo Tarbin
522c5562eb feat: Add dark mode toggle button in HomeHero component 2025-06-21 00:15:27 -04:00
Mo Tarbin
ef8c63c176 Add dark mode screenshot and enhance image styling in HomeHero component 2025-06-21 00:07:31 -04:00
Mo Tarbin
12537ec7f3 feat: Add dark mode support for screenshot in HomeHero component 2025-06-21 00:00:49 -04:00
Mo Tarbin
8b791ed19e Update button variant and remove unnecessary styles in CompactChoreCard 2025-06-20 23:55:18 -04:00
Mo Tarbin
a1fdd0c0d2 fix: Add userId to users array in DemoMyChore component 2025-06-20 23:54:55 -04:00
Mo Tarbin
0b7097082d refactor: Update export order of animation components for consistency 2025-06-20 00:38:27 -04:00
Mo Tarbin
c903192d7c Add confirmation modals for token removal and storage clearing actions 2025-06-19 12:40:33 -04:00
Mo Tarbin
d8b5e0f5a1 Enhance CompactChoreCard and MyChores with animated transitions for multi-select and search filter 2025-06-19 02:24:39 -04:00
Mo Tarbin
fb8d476c34 Add more keyboard shortcuts for search focus and multi-select mode toggle in MyChores 2025-06-19 01:32:29 -04:00
Mo Tarbin
b4652e2486 feat: Add animation components and global styles for improved UX 2025-06-18 01:19:52 -04:00
Mo Tarbin
b0d37dc997 feat: Add animation components and loading screen; implement page transitions and staggered animations 2025-06-18 01:19:14 -04:00
Mo Tarbin
778930015e refactor: Remove debug log from useSSEContext hook 2025-06-18 00:24:28 -04:00
Mo Tarbin
fb8c45a86d refactor: Remove unused user profile references and improve SSE/WebSocket connection logic 2025-06-18 00:19:18 -04:00
Mo Tarbin
13b0533277 feat: Add image compression for profile photo uploads to reduce file size 2025-06-17 18:23:43 -04:00
Mo Tarbin
6cb6b1534d Websocket and SSE in working state :
Add Server-Sent Events (SSE) support with connection status and settings components

- Implemented SSEConnectionStatus component to display real-time connection status.
- Created SSESettings component for enabling/disabling SSE based on user profile.
- Introduced SSEContext and useSSE hook for managing SSE connections and state.
- Added auto-connect functionality for SSE based on user profile and token validity.
- Updated WebSocketSettings to ensure proper handling of WebSocket state.
- Enhanced MyChores view with bulk archive functionality and improved UI feedback.
- Refactored NotificationSetting to ensure boolean values are set correctly.
- Updated Settings view to include RealTimeSettings component for SSE configuration.
2025-06-17 01:07:14 -04:00
Mo Tarbin
4098f2e498 feat: Implement multi-select functionality with keyboard shortcuts and bulk actions 2025-06-17 01:00:39 -04:00
Mo Tarbin
19093a4ead Merge branch 'websocket-support' into dev 2025-06-14 00:06:28 -04:00
Mo Tarbin
c7e2cb9d06 fix: Adjust error message formatting for better readability in multiple components 2025-06-14 00:06:25 -04:00
Mo Tarbin
6be22170d8 Enhance MFASettings alert styling and update ProfileSettings notification handling 2025-06-13 23:53:42 -04:00
Mo Tarbin
2077b0ab4c Refactor error handling and notification system
- Removed the ErrorProvider component and replaced it with a unified NotificationProvider.
- Updated all components to utilize the new NotificationProvider for displaying notifications.
- Enhanced notification types to include success, error, warning, and info with customizable messages and titles.
- Removed Snackbar components from various views and replaced them with calls to the NotificationProvider.
- Updated the ForgotPasswordView, LoginView, SignupView, and other components to handle notifications more effectively.
- Improved user experience by providing consistent notification handling across the application.
2025-06-13 23:52:02 -04:00
Mo Tarbin
bc2ca86a95 Update priority colors in Colors utility and adjust usage in CompactChoreCard 2025-06-13 17:14:55 -04:00
Mo Tarbin
a443582ca9 Implement WebSocket connection management and settings UI 2025-06-13 16:38:34 -04:00
Mo Tarbin
2162397575 Add updatedAt timestamp to UpdateChoreAssignee and UpdateDueDate functions 2025-06-10 18:55:46 -04:00
Mo Tarbin
6cfb32570b merging dev 2025-06-08 12:14:00 -04:00
Mo Tarbin
a8d66fd0a4 Merge branch 'dev' 2025-06-08 12:08:39 -04:00
Mo Tarbin
b46d3d28a9 refactor: Consolidate imports for useCircleMembers and useUserProfile in UserPoints component 2025-06-08 10:51:08 -04:00
Mo Tarbin
44372059cd refactor: Replace UserContext with useUserProfile hook in UserPoints component 2025-06-08 02:20:25 -04:00
Mo Tarbin
64668147d9 refactor: Remove UserContext as it is no longer needed 2025-06-08 02:19:33 -04:00
Mo Tarbin
e21e71b442 feat: Refactor user profile management and improve token validation
- Introduced `useUserProfile` hook to centralize user profile fetching and management.
- Updated various components to utilize the new `useUserProfile` hook instead of context.
- Enhanced token validation logic in `Fetch` function to prevent unnecessary redirects.
- Added `parseDueDate` function to handle due date parsing with improved logic.
- Cleaned up user profile state management across multiple views and settings.
- Improved loading states and error handling in user-related components.
- remove usercontext and just use react query for userProfile
2025-06-08 02:09:23 -04:00
Mo Tarbin
10f646f125 refactor: Update LoginView to use useUserProfile hook and clean up user profile handling
- fix bug cause navigation loop
2025-06-08 02:07:33 -04:00
Mo Tarbin
187b76e04c feat: Integrate NotificationTemplate component into ChoreEdit and AddTaskModal for enhanced notification management 2025-06-08 02:05:59 -04:00
Mo Tarbin
f2c36cae37 fix: Add overflowX hidden to Box in Sidepanel for improved layout 2025-06-04 00:33:05 -04:00
Mo Tarbin
77a6357ae4 Merge branch 'dev' 2025-06-03 23:43:57 -04:00
Mo Tarbin
6c1be53f86 refactor: Rename parameter in CompleteSubTask back to completedAt to match backend https://github.com/donetick/donetick/issues/224 2025-06-03 23:33:55 -04:00
Sebastiaan ten Pas
59e02f047b fix: change Notificaiton to Notification 2025-06-03 13:02:43 +01:00
Mo Tarbin
321250f30e refactor: Update due date display logic and fix performer ID reference in ChoreCard component 2025-06-03 00:22:48 -04:00
Mo Tarbin
7559036abe refactor: Update chore grouping and color constants for improved clarity and organization 2025-06-03 00:18:51 -04:00
Mo Tarbin
6080b57f8a Merge branch 'dev' 2025-06-01 00:47:57 -04:00
Mo Tarbin
ddf654a641 refactor: Consolidate chore action handling into ChoreActionMenu component and remove unused code from ChoreCard and CompactChoreCard 2025-06-01 00:47:47 -04:00
Mo Tarbin
bf8e187962 Merge branch 'dev' 2025-05-31 19:40:34 -04:00
Mo Tarbin
cf252c3ec4 refactor: Clean up unused code and improve layout in CompactChoreCard, MyChores, and AddTaskModal components 2025-05-31 19:40:23 -04:00
Mo Tarbin
d65541fb3e refactor: Simplify user data fetching in MyChores component and update performer assignment logic ( cause a racing condition where sometime no task shown) 2025-05-31 17:18:17 -04:00
Mo Tarbin
20ef99cfc7 refactor: Remove debug console logs from WelcomeCard component 2025-05-31 16:46:02 -04:00
Mo Tarbin
87a003918d Merge branch 'dev' 2025-05-31 03:42:53 -04:00
Mo Tarbin
f5c3c90f37 fix: Update legend item assignee in CalendarView 2025-05-31 03:42:01 -04:00
Mo Tarbin
ee690092ba Merge branch 'main' of https://github.com/Donetick/frontend 2025-05-31 01:40:52 -04:00
Mo Tarbin
34a386abce feat: Implement Multi-Factor Authentication (MFA) flow in LoginView and add MFA settings page
- Added MFA verification modal to handle MFA during login.
- Integrated MFA checks in login and OAuth login processes.
- Created MFASettings component to manage MFA setup, enabling, disabling, and backup codes.
- Updated ProfileSettings to include timezone selection.
- Enhanced CalendarView to display assignee names with avatars.
- Added RichTextEditor enhancements for image uploads based on user account type.
- Minor adjustments to ChoreEdit and ChoreView components for better UX.
2025-05-31 01:36:55 -04:00
Mo Tarbin
05f4c42bf9 Enhance user experience with Plus feature notifications and improve code structure
- Updated ChoreEdit and RepeatSection components to provide clearer messaging for Basic plan users regarding Plus features.
- Introduced CompactChoreCard component to streamline chore display options in MyChores.
- Implemented view mode toggle in MyChores for better user preference handling.
- Refactored StorageSettings to conditionally display storage usage information based on user plan.
- Improved error handling and user feedback across various components.
2025-05-30 14:46:26 -04:00
Mo Tarbin
1510dc9bc2 Only show " Nothing scheduled" when there really nothing to show. fix where it was shown with archive tasks 2025-05-29 01:32:37 -04:00
Mo Tarbin
2a85b621f5 style: update Calendar styles for improved UI consistency; enhance CalendarView layout and chore display logic 2025-05-29 01:02:19 -04:00
Mo Tarbin
97abf2f230 fix: update CompleteSubTask parameter name and adjust body payload; enhance Sidepanel layout and restore ActivitiesCard position; modify WelcomeCard styles for improved UI consistency 2025-05-29 01:02:12 -04:00
Mo Tarbin
1f2d38730d feat: implement ActivitiesCard component to display recent activities with enhanced status and time display
Support the new Status and Performed By
2025-05-29 01:01:07 -04:00
Mo Tarbin
5c000f50aa feat: enhance Sidepanel with chore history integration and improve Calendar styles 2025-05-28 00:45:25 -04:00
Mo Tarbin
581931b679 Improve calendar styles and improve chore display logic in CalendarView 2025-05-28 00:11:46 -04:00
Mo Tarbin
709a91b1db Your commit message 2025-05-27 11:58:52 -04:00
Mo Tarbin
6ddb8d01ec feat: add profile and storage settings components, integrate rich text editor, and implement image compression for uploads 2025-05-27 02:18:59 -04:00
Mo Tarbin
81d3144da2 Fix and populating timezone. https://github.com/donetick/donetick/issues/197 2025-05-26 01:45:56 -04:00
Mohamad Tarbin
be2e8b7169 Merge pull request #23 from ssddanbrown/homepage_grammar
Fixed & adjusted a range of casing/wording on the homepage
2025-05-16 22:08:53 -04:00
Mo Tarbin
a21774031b Packagelock 2025-05-16 21:16:52 -04:00
Mo Tarbin
de4dc9b9a0 fix: update version to 0.1.101 in package-lock.json 2025-05-16 20:48:08 -04:00
Mo Tarbin
7ae2859c78 fix: update version to 0.1.101 in package.json 2025-05-16 20:38:50 -04:00
Mo Tarbin
8228472031 fix: integrate useResource hook in App component and update queryKey in useResource 2025-05-16 20:38:00 -04:00
Dan Brown
7ca5a2bd02 Fixed & adjusted a range of casing/wording on the homepage 2025-05-07 14:56:25 +01:00
Mo Tarbin
8858c7f619 Support cloning task https://github.com/donetick/donetick/issues/200 2025-05-07 00:28:23 -04:00
Mo Tarbin
992d7e3303 fix: update ApiManager to handle navigation on 401 Unauthorized responses and navigation for login 2025-05-07 00:21:36 -04:00
Mo Tarbin
bce135cba8 fix: improve date comparison in CalendarView 2025-05-07 00:19:54 -04:00
Mo Tarbin
8c30bedefb Fix authentication with OIDC 2025-05-07 00:05:44 -04:00
Mo Tarbin
e26f2910f3 style: remove fixed height from task input for better responsiveness 2025-04-24 22:10:30 -04:00
Mo Tarbin
0b1208a11c fix: update variable names in renderHighlightedSentence for clarity 2025-04-24 21:56:07 -04:00
Mo Tarbin
261919f17a refactor: update priority parsing to use '!' prefix and enhance highlight handling in CustomParsers 2025-04-24 21:34:07 -04:00
Mo Tarbin
4206cbd557 chore: update dependencies to version 7.0.0 and above, including Capacitor packages and MUI icons 2025-04-24 20:51:01 -04:00
Mohamad Tarbin
edc203c9ed Merge pull request #22 from donetick/smart-text-field
Smart Input Field and Limit offline support
2025-04-24 01:15:38 -04:00
337 changed files with 66573 additions and 12310 deletions

2
.bundle/config Normal file
View File

@@ -0,0 +1,2 @@
---
BUNDLE_PATH: "vendor/bundle"

9
.editorconfig Normal file
View File

@@ -0,0 +1,9 @@
# EditorConfig is awesome: https://EditorConfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true

2
.env
View File

@@ -1,4 +1,4 @@
VITE_APP_API_URL=http://localhost:2021
VITE_IS_LANDING_DEFAULT=false
VITE_IS_LANDING_DEFAULT=true
VITE_OPENREPLAY_PROJECT_KEY=
VITE_IS_SELF_HOSTED=false

View File

@@ -2,3 +2,4 @@ VITE_APP_API_URL=http://localhost:2021
VITE_APP_REDIRECT_URL=http://localhost:5173
VITE_APP_GOOGLE_CLIENT_ID=USE_YOUR_OWN_CLIENT_ID
VITE_IS_SELF_HOSTED=true
VITE_IS_LANDING_DEFAULT=true

View File

@@ -2,39 +2,20 @@ name: Build validation
on:
push:
branches: [ "main", "develop" ]
branches: [main]
pull_request:
branches: [ "main", "develop" ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20.x, 22.x]
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
- name: Use Node.js 20
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
node-version: 20.x
cache: 'npm'
- name: Install dependencies
run: npm i
- run: npm run build
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js 22
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
- name: Install dependencies
run: npm i
# Lint currently reporting lots of preexisting issues
# - run: npm run lint

22
.gitignore vendored
View File

@@ -23,4 +23,24 @@ dist-ssr
*.sln
*.sw?
resources/android/**/*
resources/android/**/*
resources/ios/**/*
# Secrets (pulled via scripts/pull-secrets.sh)
.env.production
android/app/google-services.json
android/app/release/*.jks
android/keystore.properties
android/local.properties
android/play-service-account.json
ios/App/App/GoogleService-Info.plist
ios/*.p8
# Release build outputs
build/android
build/ios
fastlane/report.xml
fastlane/Preview.html
fastlane/.env
fastlane/*.log
vendor/bundle

2
.npmrc Normal file
View File

@@ -0,0 +1,2 @@
fund=false
audit=false

1
.nvmrc Normal file
View File

@@ -0,0 +1 @@
20

85
AUTOMATED_RELEASE.md Normal file
View File

@@ -0,0 +1,85 @@
# Automated Release Pipeline
Builds and (optionally) uploads signed Android and iOS release artifacts from the CLI — no Android Studio or Xcode GUI needed for routine releases.
## Quick start
```sh
./scripts/pull-secrets.sh # pulls all signing secrets from Vaultwarden
./scripts/release.sh # bump patch version, build + sign both platforms
./scripts/release.sh --upload # also upload: Android → Play internal track, iOS → TestFlight
```
Common flags on `release.sh`:
| Flag | Effect |
|---|---|
| `--android` / `--ios` | Build only one platform |
| `--bump minor\|major` | Bump type (default: `patch`) |
| `--skip-bump` | Build with the current version, don't bump |
| `--upload` | Upload after building |
| `--track TRACK` | Play Store track for `--upload` (default: `internal`) |
Outputs:
- Android: `android/app/build/outputs/bundle/release/app-release.aab`
- iOS: `build/ios/Donetick.ipa`
## One-time machine setup
1. `bundle install` — installs fastlane (Ruby gems, local to the repo via `vendor/bundle`)
2. `./scripts/pull-secrets.sh` — pulls all secrets below from Vaultwarden
3. `android/local.properties` needs `sdk.dir=<path to Android SDK>` — not pulled from vault, machine-specific. Android Studio creates this automatically; if building headless-only, create it manually.
4. Export `ASC_ISSUER_ID` (App Store Connect API key issuer ID) — either in your shell profile, or add it to the `Donetick Env Production` vault note so `pull-secrets.sh` delivers it into `.env.production` (which `release.sh` auto-sources).
5. A working Apple Distribution certificate + the `Donetick App Store(fastline)` provisioning profile must be installed in your keychain / `~/Library/MobileDevice/Provisioning Profiles/` (see "iOS signing model" below) — **not** currently pulled from vault, machine-specific one-time setup.
## Secrets pulled by `scripts/pull-secrets.sh`
All secrets live in Vaultwarden (`https://www.bitwarden.com`) as Secure Notes, named exactly as below:
| Vault item name | Written to | Encoding |
|---|---|---|
| Donetick Google Services Android | `android/app/google-services.json` | raw |
| Donetick Android Keystore | `android/app/release/donetick.jks` | base64 |
| Donetick Keystore Password | (used inline for `android/keystore.properties`) | raw |
| Donetick Google Play Service Account | `android/play-service-account.json` | raw |
| Donetick Google Services iOS | `ios/App/App/GoogleService-Info.plist` | raw |
| Donetick App Store Connect Key | `ios/AuthKey_84F695CDQ3.p8` | base64 |
| Donetick Env Production | `.env.production` | raw |
None of these files are committed to git — all covered by `.gitignore`.
## iOS signing model (important — don't relitigate this)
The App target uses **manual signing for Release**, not Automatic. This was a deliberate choice, not the default:
- The project has **two** Apple Distribution-type certificates on the Apple Developer account: an Xcode Cloudmanaged one (private key never leaves Apple, can't be used for local CLI signing) and a plain one created via Xcode → Settings → Accounts → Manage Certificates (private key is in the local keychain, usable). Automatic signing kept binding to the wrong (Managed) one.
- Fix: `ios/App/App.xcodeproj/project.pbxproj` → App target → Release config has `CODE_SIGN_STYLE = Manual`, `CODE_SIGN_IDENTITY = "Apple Distribution"`, `PROVISIONING_PROFILE_SPECIFIER = "Donetick App Store(fastline)"`. Debug config is untouched (still Automatic, for local dev builds in Xcode).
- `fastlane/Fastfile`'s `ios release` lane passes explicit `export_options: { signingStyle: "manual", provisioningProfiles: {...} }` to `build_app` — do **not** switch this back to `-allowProvisioningUpdates`/automatic without a good reason, it re-triggers the ambiguous cert selection.
**If you ever add/change an entitlement** (new Capability in Signing & Capabilities, e.g. a new permission), the existing provisioning profile becomes stale and exports will fail with an error like `"App.app" requires a provisioning profile with the X feature`. Fix:
1. developer.apple.com → Identifiers → `com.donetick.app` → confirm the new capability is checked
2. developer.apple.com → Profiles → find `Donetick App Store(fastline)` → regenerate it → download
3. Install it locally: get its UUID (`security cms -D -i <file>.mobileprovision | plutil -extract UUID xml1 -o - -`) and copy to `~/Library/MobileDevice/Provisioning Profiles/<uuid>.mobileprovision`
**If the Distribution certificate ever expires/is revoked**, redo the one-time Xcode step: Settings → Accounts → Manage Certificates → `+` → Apple Distribution, then regenerate the profile as above.
## Android signing model
Standard keystore signing via `android/keystore.properties`, read by `android/app/build.gradle`. One historical gotcha already fixed: `storeFile` must be `release/donetick.jks` (relative to the `android/app` module dir), **not** `app/release/donetick.jks` — that extra `app/` silently resolved to a double-nested wrong path and broke CLI builds (Android Studio may have masked this before).
## Play Store upload gotchas
- The service account (`fastline-471@donetick-5f910.iam.gserviceaccount.com`) needs the **Google Play Android Developer API enabled** in its GCP project (`donetick-5f910`), **and** explicit per-app release permission granted in Play Console → Users and permissions (not just account-level access) — **and you have to actually click Save**, the UI will silently not persist it otherwise.
- Google Play Console permission changes can take time to propagate on Google's backend even after saving (historically documented as up to ~24h, though in practice it was near-instant once actually saved).
- The Play Developer API requires the app to have had **at least one manual release** uploaded through the Play Console website before API uploads work at all — not an issue for Donetick (already satisfied) but relevant if this is ever set up for a brand-new app.
## Fastlane lanes reference
```sh
bundle exec fastlane android release # build signed .aab
bundle exec fastlane android apk # build signed .apk (sideloading/testing)
bundle exec fastlane android upload [track:X] # upload .aab to Play Store (default track: internal)
bundle exec fastlane ios release # build signed .ipa
bundle exec fastlane ios upload # upload .ipa to TestFlight
```

3
Gemfile Normal file
View File

@@ -0,0 +1,3 @@
source "https://rubygems.org"
gem "fastlane"

233
Gemfile.lock Normal file
View File

@@ -0,0 +1,233 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.9)
abbrev (0.1.2)
addressable (2.9.0)
public_suffix (>= 2.0.2, < 8.0)
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.3.2)
aws-partitions (1.1109.0)
aws-sdk-core (3.224.1)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
aws-sigv4 (~> 1.9)
base64
jmespath (~> 1, >= 1.6.1)
logger
aws-sdk-kms (1.101.0)
aws-sdk-core (~> 3, >= 3.216.0)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.188.0)
aws-sdk-core (~> 3, >= 3.224.1)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.11.0)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
base64 (0.2.0)
claide (1.1.0)
colored (1.2)
colored2 (3.1.2)
commander (4.6.0)
highline (~> 2.0.0)
csv (3.3.5)
declarative (0.0.20)
digest-crc (0.7.0)
rake (>= 12.0.0, < 14.0.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.8.1)
emoji_regex (3.2.3)
excon (0.109.0)
faraday (1.10.6)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
faraday-httpclient (~> 1.0)
faraday-multipart (~> 1.0)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.0)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
ruby2_keywords (>= 0.0.4)
faraday-cookie_jar (0.0.8)
faraday (>= 0.8.0)
http-cookie (>= 1.0.0)
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.1)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.2.0)
multipart-post (~> 2.0)
faraday-net_http (1.0.2)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.4)
faraday_middleware (1.2.1)
faraday (~> 1.0)
fastimage (2.4.1)
fastlane (2.230.0)
CFPropertyList (>= 2.3, < 4.0.0)
abbrev (~> 0.1.2)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
aws-sdk-s3 (~> 1.0)
babosa (>= 1.0.3, < 2.0.0)
base64 (~> 0.2.0)
bundler (>= 1.12.0, < 3.0.0)
colored (~> 1.2)
commander (~> 4.6)
csv (~> 3.3)
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (>= 0.1, < 4.0)
excon (>= 0.71.0, < 1.0.0)
faraday (~> 1.0)
faraday-cookie_jar (~> 0.0.6)
faraday_middleware (~> 1.0)
fastimage (>= 2.1.0, < 3.0.0)
fastlane-sirp (>= 1.0.0)
gh_inspector (>= 1.1.2, < 2.0.0)
google-apis-androidpublisher_v3 (~> 0.3)
google-apis-playcustomapp_v1 (~> 0.1)
google-cloud-env (>= 1.6.0, < 2.0.0)
google-cloud-storage (~> 1.31)
highline (~> 2.0)
http-cookie (~> 1.0.5)
json (< 3.0.0)
jwt (>= 2.1.0, < 3)
logger (>= 1.6, < 2.0)
mini_magick (>= 4.9.4, < 5.0.0)
multipart-post (>= 2.0.0, < 3.0.0)
mutex_m (~> 0.3.0)
naturally (~> 2.2)
nkf (~> 0.2.0)
optparse (>= 0.1.1, < 1.0.0)
plist (>= 3.1.0, < 4.0.0)
rubyzip (>= 2.0.0, < 3.0.0)
security (= 0.1.5)
simctl (~> 1.6.3)
terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (~> 3)
tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0)
xcodeproj (>= 1.13.0, < 2.0.0)
xcpretty (~> 0.4.1)
xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
fastlane-sirp (1.1.0)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.54.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-core (0.11.3)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
mini_mime (~> 1.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.a)
rexml
google-apis-iamcredentials_v1 (0.17.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-playcustomapp_v1 (0.13.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-storage_v1 (0.29.0)
google-apis-core (>= 0.11.0, < 2.a)
google-cloud-core (1.6.1)
google-cloud-env (>= 1.0, < 3.a)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.3.1)
google-cloud-storage (1.45.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.29.0)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.8.1)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
highline (2.0.3)
http-cookie (1.0.8)
domain_name (~> 0.5)
httpclient (2.9.0)
mutex_m
jmespath (1.6.2)
json (2.7.6)
jwt (2.10.3)
base64
logger (1.7.0)
mini_magick (4.13.2)
mini_mime (1.1.5)
multi_json (1.15.0)
multipart-post (2.4.1)
mutex_m (0.3.0)
nanaimo (0.4.0)
naturally (2.3.0)
nkf (0.2.0)
optparse (0.8.1)
os (1.1.4)
plist (3.7.2)
public_suffix (5.1.1)
rake (13.4.2)
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.8.0)
rexml (3.4.4)
rouge (3.28.0)
ruby2_keywords (0.0.5)
rubyzip (2.4.1)
security (0.1.5)
signet (0.18.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.10)
CFPropertyList
naturally
terminal-notifier (2.0.0)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
trailblazer-option (0.1.2)
tty-cursor (0.7.1)
tty-screen (0.8.2)
tty-spinner (0.9.3)
tty-cursor (~> 0.7)
uber (0.1.0)
unf (0.2.0)
unicode-display_width (2.6.0)
word_wrap (1.0.0)
xcodeproj (1.28.1)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
base64
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.4.0)
nkf
rexml (>= 3.3.6, < 4.0)
xcpretty (0.4.1)
rouge (~> 3.28.0)
xcpretty-travis-formatter (1.0.1)
xcpretty (~> 0.2, >= 0.0.7)
PLATFORMS
ruby
DEPENDENCIES
fastlane
BUNDLED WITH
1.17.2

View File

@@ -20,12 +20,9 @@ As an avid for open-source, I was eager to create a solution that could benefit
- Recurring Tasks: Schedule tasks to repeat daily, weekly, monthly, or yearly, with flexible customization options.
- Progress Tracking: Track the completion status of tasks and view historical data.
## Installation
## Development Environment
1. Clone the repository:
2. Navigate to the project directory: `cd frontend`
3. Download dependency `npm install`
4. Run locally `npm start`
Follow the full instructions here: https://github.com/donetick/donetick?tab=readme-ov-file#development-environment
## Contributing
@@ -41,7 +38,7 @@ Contributions are welcome! If you would like to contribute to Donetick, please f
Donetick is a work in progress and has been a fantastic learning experience for me as I've honed my React skills,I'm looking for collaborators to help improve and refine the Donetick. Feel free to open PR or suggest changes.
## Plans :
## Plans:
My goal is to expand Donetick by offering a hosted infrastructure option. This will make it even easier for users to access and utilize Donetick's features without the need for self-hosting.

View File

@@ -1,5 +1,11 @@
apply plugin: 'com.android.application'
def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
namespace "com.donetick.app"
compileSdk rootProject.ext.compileSdkVersion
@@ -7,8 +13,8 @@ android {
applicationId "com.donetick.app"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
versionCode 37
versionName "1.2.16"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
@@ -16,8 +22,19 @@ android {
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
}
}
signingConfigs {
release {
if (keystorePropertiesFile.exists()) {
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
}
}
}
buildTypes {
release {
signingConfig keystorePropertiesFile.exists() ? signingConfigs.release : signingConfigs.debug
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}

View File

@@ -9,13 +9,22 @@ android {
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies {
implementation project(':capacitor-community-sqlite')
implementation project(':capacitor-app')
implementation project(':capacitor-browser')
implementation project(':capacitor-device')
implementation project(':capacitor-local-llm')
implementation project(':capacitor-local-notifications')
implementation project(':capacitor-network')
implementation project(':capacitor-preferences')
implementation project(':capacitor-push-notifications')
implementation project(':capacitor-status-bar')
implementation project(':capgo-capacitor-document-scanner')
implementation project(':capgo-capacitor-nfc')
implementation project(':capgo-capacitor-social-login')
implementation project(':jcesarmobile-capacitor-ocr')
implementation project(':revenuecat-purchases-capacitor')
implementation project(':revenuecat-purchases-capacitor-ui')
implementation project(':capacitor-plugin-safe-area')
}

View File

@@ -0,0 +1,37 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.donetick.app",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 25,
"versionName": "1.2.3",
"outputFile": "app-release.apk"
}
],
"elementType": "File",
"baselineProfiles": [
{
"minApi": 28,
"maxApi": 30,
"baselineProfiles": [
"baselineProfiles/1/app-release.dm"
]
},
{
"minApi": 31,
"maxApi": 2147483647,
"baselineProfiles": [
"baselineProfiles/0/app-release.dm"
]
}
],
"minSdkVersionForDexing": 28
}

View File

@@ -1,14 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation"
android:name=".MainActivity"
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBarLaunch"
@@ -18,6 +20,21 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- Deep link intent filter for OAuth and other donetick:// URLs -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="donetick" />
</intent-filter>
<!-- NFC NDEF dispatch: open app directly when a donetick:// tag is scanned -->
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="donetick" />
</intent-filter>
</activity>
<provider
@@ -27,9 +44,29 @@
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
</provider>
<!-- Push Notifications Icon -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@mipmap/ic_launcher" />
<!-- Push Notifications Color -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@android:color/white" />
</application>
<!-- Permissions -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
<!-- Android 14+ partial photo access via system photo picker; no READ_MEDIA_IMAGES needed -->
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
<!-- Explicitly block READ_MEDIA_IMAGES if any library injects it -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" tools:node="remove" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" tools:node="remove" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.NFC" />
</manifest>

View File

@@ -2,4 +2,48 @@ package com.donetick.app;
import com.getcapacitor.BridgeActivity;
public class MainActivity extends BridgeActivity {}
import ee.forgr.capacitor.social.login.GoogleProvider;
import ee.forgr.capacitor.social.login.SocialLoginPlugin;
import ee.forgr.capacitor.social.login.ModifiedMainActivityForSocialLoginPlugin;
import com.getcapacitor.PluginHandle;
import com.getcapacitor.Plugin;
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.util.Log;
public class MainActivity extends BridgeActivity implements ModifiedMainActivityForSocialLoginPlugin {
// Capacitor only forwards ACTION_VIEW deep links, so normalize Donetick NFC intents before dispatch.
@Override
protected void onNewIntent(Intent intent) {
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())
&& intent.getData() != null
&& "donetick".equals(intent.getData().getScheme())) {
intent.setAction(Intent.ACTION_VIEW);
}
super.onNewIntent(intent);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode >= GoogleProvider.REQUEST_AUTHORIZE_GOOGLE_MIN && requestCode < GoogleProvider.REQUEST_AUTHORIZE_GOOGLE_MAX) {
PluginHandle pluginHandle = getBridge().getPlugin("SocialLogin");
if (pluginHandle == null) {
Log.i("Google Activity Result", "SocialLogin login handle is null");
return;
}
Plugin plugin = pluginHandle.getInstance();
if (!(plugin instanceof SocialLoginPlugin)) {
Log.i("Google Activity Result", "SocialLogin plugin instance is not SocialLoginPlugin");
return;
}
((SocialLoginPlugin) plugin).handleGoogleLoginIntent(requestCode, data);
}
}
@Override
public void IHaveModifiedTheMainActivityForTheUseWithSocialLoginPlugin() {}
}

View File

@@ -7,8 +7,8 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.2.1'
classpath 'com.google.gms:google-services:4.4.0'
classpath 'com.android.tools.build:gradle:8.10.1'
classpath 'com.google.gms:google-services:4.4.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files

View File

@@ -2,15 +2,27 @@
include ':capacitor-android'
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
include ':capacitor-community-sqlite'
project(':capacitor-community-sqlite').projectDir = new File('../node_modules/@capacitor-community/sqlite/android')
include ':capacitor-app'
project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android')
include ':capacitor-browser'
project(':capacitor-browser').projectDir = new File('../node_modules/@capacitor/browser/android')
include ':capacitor-device'
project(':capacitor-device').projectDir = new File('../node_modules/@capacitor/device/android')
include ':capacitor-local-llm'
project(':capacitor-local-llm').projectDir = new File('../node_modules/@capacitor/local-llm/android')
include ':capacitor-local-notifications'
project(':capacitor-local-notifications').projectDir = new File('../node_modules/@capacitor/local-notifications/android')
include ':capacitor-network'
project(':capacitor-network').projectDir = new File('../node_modules/@capacitor/network/android')
include ':capacitor-preferences'
project(':capacitor-preferences').projectDir = new File('../node_modules/@capacitor/preferences/android')
@@ -20,8 +32,23 @@ project(':capacitor-push-notifications').projectDir = new File('../node_modules/
include ':capacitor-status-bar'
project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android')
include ':capgo-capacitor-document-scanner'
project(':capgo-capacitor-document-scanner').projectDir = new File('../node_modules/@capgo/capacitor-document-scanner/android')
include ':capgo-capacitor-nfc'
project(':capgo-capacitor-nfc').projectDir = new File('../node_modules/@capgo/capacitor-nfc/android')
include ':capgo-capacitor-social-login'
project(':capgo-capacitor-social-login').projectDir = new File('../node_modules/@capgo/capacitor-social-login/android')
include ':jcesarmobile-capacitor-ocr'
project(':jcesarmobile-capacitor-ocr').projectDir = new File('../node_modules/@jcesarmobile/capacitor-ocr/android')
include ':revenuecat-purchases-capacitor'
project(':revenuecat-purchases-capacitor').projectDir = new File('../node_modules/@revenuecat/purchases-capacitor/android')
include ':revenuecat-purchases-capacitor-ui'
project(':revenuecat-purchases-capacitor-ui').projectDir = new File('../node_modules/@revenuecat/purchases-capacitor-ui/android')
include ':capacitor-plugin-safe-area'
project(':capacitor-plugin-safe-area').projectDir = new File('../node_modules/capacitor-plugin-safe-area/android')

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View File

@@ -1,16 +1,17 @@
ext {
minSdkVersion = 22
compileSdkVersion = 34
targetSdkVersion = 34
androidxActivityVersion = '1.8.0'
androidxAppCompatVersion = '1.6.1'
androidxCoordinatorLayoutVersion = '1.2.0'
androidxCoreVersion = '1.12.0'
androidxFragmentVersion = '1.6.2'
minSdkVersion = 28
compileSdkVersion = 36
targetSdkVersion = 36
androidxActivityVersion = '1.11.0'
androidxAppCompatVersion = '1.7.1'
androidxCoordinatorLayoutVersion = '1.3.0'
androidxCoreVersion = '1.17.0'
androidxFragmentVersion = '1.8.9'
coreSplashScreenVersion = '1.0.1'
androidxWebkitVersion = '1.9.0'
androidxWebkitVersion = '1.14.0'
junitVersion = '4.13.2'
androidxJunitVersion = '1.1.5'
androidxEspressoCoreVersion = '3.5.1'
androidxJunitVersion = '1.3.0'
androidxEspressoCoreVersion = '3.7.0'
cordovaAndroidVersion = '10.1.1'
}
firebaseMessagingVersion = '24.1.0'
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 KiB

84
bump-version.js Executable file
View File

@@ -0,0 +1,84 @@
#!/usr/bin/env node
import { execSync } from 'child_process'
import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
// Read package.json
const packageJsonPath = path.join(__dirname, 'package.json')
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
// Get current version
const currentVersion = packageJson.version
console.log(`Current version: ${currentVersion}`)
// Parse version (assuming semver format: major.minor.patch)
const versionParts = currentVersion.split('.').map(Number)
const [major, minor, patch] = versionParts
// Bump patch version by default (can be modified to accept arguments for major/minor)
const bumpType = process.argv[2] || 'patch'
let newVersion
switch (bumpType) {
case 'major':
newVersion = `${major + 1}.0.0`
break
case 'minor':
newVersion = `${major}.${minor + 1}.0`
break
case 'patch':
default:
newVersion = `${major}.${minor}.${patch + 1}`
break
}
console.log(`New version: ${newVersion}`)
// Update package.json
packageJson.version = newVersion
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n')
console.log('✓ Updated package.json')
// Read Android build.gradle to get current versionCode
const buildGradlePath = path.join(__dirname, 'android', 'app', 'build.gradle')
let buildGradle = fs.readFileSync(buildGradlePath, 'utf8')
// Extract current versionCode
const versionCodeMatch = buildGradle.match(/versionCode\s+(\d+)/)
const currentVersionCode = versionCodeMatch ? parseInt(versionCodeMatch[1]) : 1
const newVersionCode = currentVersionCode + 1
console.log(`Android versionCode: ${currentVersionCode}${newVersionCode}`)
// Use capacitor-set-version to update both iOS and Android
try {
console.log('\nUpdating iOS and Android versions...')
// Set version and build number for both platforms
execSync(
`npx capacitor-set-version set -v ${newVersion} -b ${newVersionCode}`,
{
stdio: 'inherit',
},
)
console.log('\n✓ Successfully bumped version to', newVersion)
console.log(`✓ Build number: ${newVersionCode}`)
console.log('\nNext steps:')
console.log('1. Review the changes')
console.log(
'2. Commit: git add . && git commit -m "Bump version to ' +
newVersion +
'"',
)
console.log('3. Tag: git tag v' + newVersion)
console.log('4. Push: git push origin develop --tags')
} catch (error) {
console.error('Error updating versions:', error.message)
process.exit(1)
}

View File

@@ -1,26 +1,28 @@
import type { CapacitorConfig } from '@capacitor/cli';
import type { CapacitorConfig } from '@capacitor/cli'
const config: CapacitorConfig = {
appId: 'com.donetick.app',
appName: 'Donetick',
webDir: 'dist',
android: {
allowMixedContent: true,
},
plugins: {
PushNotifications: {
presentationOptions: ['badge', 'sound', 'alert'],
},
LocalNotifications: {
smallIcon: "ic_stat_icon_config_sample",
iconColor: "#488AFF",
sound: "beep.wav",
smallIcon: 'ic_stat_icon_config_sample',
iconColor: '#488AFF',
sound: 'beep.wav',
},
GoogleAuth: {
scopes: ['profile', 'email', 'openid'],
clientId: process.env.VITE_APP_GOOGLE_CLIENT_ID,
androidClientId: process.env.VITE_APP_ANDRIOD_CLIENT_ID,
iosClientId: process.env.VITE_APP_IOS_CLIENT_ID,
// GoogleAuth: {
// scopes: ['profile', 'email', 'openid'],
// clientId: process.env.VITE_APP_GOOGLE_CLIENT_ID,
// androidClientId: process.env.VITE_APP_ANDRIOD_CLIENT_ID,
// iosClientId: process.env.VITE_APP_IOS_CLIENT_ID,
// },
},
}
};
export default config;
export default config

15
crowdin.yml Normal file
View File

@@ -0,0 +1,15 @@
# Crowdin configuration for Donetick
# See: https://support.crowdin.com/configuration-file/
project_id: "donetick"
api_token_env: CROWDIN_API_TOKEN
preserve_hierarchy: true
languages_mapping:
two_letters_code:
zh-CN: zh-CN
files:
- source: /public/locales/en/*.json
translation: /public/locales/%two_letters_code%/%original_file_name%
update_option: update_as_unapproved

4
fastlane/Appfile Normal file
View File

@@ -0,0 +1,4 @@
app_identifier("com.donetick.app")
team_id("6UJJ78R3BS")
apple_id(ENV["APPLE_ID"]) if ENV["APPLE_ID"]

113
fastlane/Fastfile Normal file
View File

@@ -0,0 +1,113 @@
require "shellwords"
default_platform(:ios)
IOS_KEY_PATH = File.expand_path("../ios/AuthKey_84F695CDQ3.p8")
IOS_OUTPUT_DIR = File.expand_path("../build/ios")
ANDROID_PROJECT_DIR = File.expand_path("../android")
PLAY_JSON_KEY_PATH = File.expand_path("../android/play-service-account.json")
platform :ios do
desc "Build a signed, App Store-ready .ipa"
lane :release do
Dir.chdir(File.expand_path("../ios/App")) do
Bundler.with_clean_env do
sh("pod install --repo-update")
end
end
build_app(
workspace: "ios/App/App.xcworkspace",
scheme: "App",
export_method: "app-store",
output_directory: IOS_OUTPUT_DIR,
output_name: "Donetick.ipa",
export_options: {
signingStyle: "manual",
provisioningProfiles: {
"com.donetick.app" => "Donetick App Store(fastline)",
},
},
)
UI.success("Signed .ipa at #{IOS_OUTPUT_DIR}/Donetick.ipa")
end
desc "Upload the built .ipa to TestFlight"
lane :upload do
UI.user_error!("Missing #{IOS_KEY_PATH} — run scripts/pull-secrets.sh first") unless File.exist?(IOS_KEY_PATH)
UI.user_error!("ASC_ISSUER_ID is not set (App Store Connect API key issuer id)") if ENV["ASC_ISSUER_ID"].to_s.empty?
ipa_path = File.join(IOS_OUTPUT_DIR, "Donetick.ipa")
UI.user_error!("Missing #{ipa_path} — run `fastlane ios release` first") unless File.exist?(ipa_path)
api_key = app_store_connect_api_key(
key_id: ENV["ASC_KEY_ID"] || "84F695CDQ3",
issuer_id: ENV["ASC_ISSUER_ID"],
key_filepath: IOS_KEY_PATH,
duration: 1200,
in_house: false,
)
upload_to_testflight(
api_key: api_key,
ipa: ipa_path,
skip_waiting_for_build_processing: true,
skip_submission: true,
)
UI.success("Uploaded to TestFlight")
end
end
platform :android do
desc "Build a signed release .aab"
lane :release do
keystore_properties = File.join(ANDROID_PROJECT_DIR, "keystore.properties")
UI.user_error!("Missing #{keystore_properties} — run scripts/pull-secrets.sh first") unless File.exist?(keystore_properties)
gradle(
task: "bundle",
build_type: "Release",
project_dir: "#{ANDROID_PROJECT_DIR}/",
)
aab_path = lane_context[SharedValues::GRADLE_AAB_OUTPUT_PATH]
UI.success("Signed .aab at #{aab_path}")
end
desc "Build a signed release .apk (for sideloading/testing)"
lane :apk do
keystore_properties = File.join(ANDROID_PROJECT_DIR, "keystore.properties")
UI.user_error!("Missing #{keystore_properties} — run scripts/pull-secrets.sh first") unless File.exist?(keystore_properties)
gradle(
task: "assemble",
build_type: "Release",
project_dir: "#{ANDROID_PROJECT_DIR}/",
)
apk_path = lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH]
UI.success("Signed .apk at #{apk_path}")
end
desc "Upload the built .aab to the Play Store (internal testing track by default)"
lane :upload do |options|
UI.user_error!("Missing #{PLAY_JSON_KEY_PATH} — run scripts/pull-secrets.sh first") unless File.exist?(PLAY_JSON_KEY_PATH)
aab_path = File.join(ANDROID_PROJECT_DIR, "app/build/outputs/bundle/release/app-release.aab")
UI.user_error!("Missing #{aab_path} — run `fastlane android release` first") unless File.exist?(aab_path)
upload_to_play_store(
json_key: PLAY_JSON_KEY_PATH,
package_name: "com.donetick.app",
aab: aab_path,
track: options[:track] || "internal",
skip_upload_metadata: true,
skip_upload_images: true,
skip_upload_screenshots: true,
)
UI.success("Uploaded to Play Store (#{options[:track] || 'internal'} track)")
end
end

69
fastlane/README.md Normal file
View File

@@ -0,0 +1,69 @@
fastlane documentation
----
# Installation
Make sure you have the latest version of the Xcode command line tools installed:
```sh
xcode-select --install
```
For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane)
# Available Actions
## iOS
### ios release
```sh
[bundle exec] fastlane ios release
```
Build a signed, App Store-ready .ipa
### ios upload
```sh
[bundle exec] fastlane ios upload
```
Upload the built .ipa to TestFlight
----
## Android
### android release
```sh
[bundle exec] fastlane android release
```
Build a signed release .aab
### android apk
```sh
[bundle exec] fastlane android apk
```
Build a signed release .apk (for sideloading/testing)
### android upload
```sh
[bundle exec] fastlane android upload
```
Upload the built .aab to the Play Store (internal testing track by default)
----
This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.
More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools).
The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools).

View File

@@ -3,8 +3,13 @@
<head>
<meta charset="UTF-8" />
<!-- <link rel="icon" type="image/svg+xml" href="/logo.svg" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- <title>FE Template</title> -->
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
/>
<title>Donetick</title>
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />

View File

@@ -14,6 +14,7 @@
504EC30F1FED79650016851F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30E1FED79650016851F /* Assets.xcassets */; };
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; };
50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; };
72FA9293C4A649D1BA0E5917 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 71866EB277374608AD02C137 /* PrivacyInfo.xcprivacy */; };
A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; };
D1115B492C653D60004C6043 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = D1115B482C653D60004C6043 /* GoogleService-Info.plist */; };
/* End PBXBuildFile section */
@@ -28,6 +29,7 @@
504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = "<group>"; };
71866EB277374608AD02C137 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; };
AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = "<group>"; };
D1115B482C653D60004C6043 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
@@ -62,6 +64,7 @@
504EC3051FED79650016851F /* Products */,
7F8756D8B27F46E3366F6CEA /* Pods */,
27E2DDA53C4D2A4D1A88CE4A /* Frameworks */,
71866EB277374608AD02C137 /* PrivacyInfo.xcprivacy */,
);
sourceTree = "<group>";
};
@@ -127,8 +130,8 @@
504EC2FC1FED79650016851F /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 0920;
LastSwiftUpdateCheck = 920;
LastUpgradeCheck = 920;
TargetAttributes = {
504EC3031FED79650016851F = {
CreatedOnToolsVersion = 9.2;
@@ -169,6 +172,7 @@
504EC30D1FED79650016851F /* Main.storyboard in Resources */,
2FAD9763203C412B000D30F8 /* config.xml in Resources */,
D1115B492C653D60004C6043 /* GoogleService-Info.plist in Resources */,
72FA9293C4A649D1BA0E5917 /* PrivacyInfo.xcprivacy in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -270,7 +274,6 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -289,7 +292,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -327,7 +330,6 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
@@ -340,7 +342,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
@@ -353,18 +355,17 @@
baseConfigurationReference = FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES;
CODE_SIGN_ENTITLEMENTS = App/App.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 37;
DEVELOPMENT_TEAM = 6UJJ78R3BS;
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0;
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
MARKETING_VERSION = 1.2.16;
PRODUCT_BUNDLE_IDENTIFIER = com.donetick.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
@@ -375,14 +376,17 @@
baseConfigurationReference = AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES;
CODE_SIGN_ENTITLEMENTS = App/App.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CODE_SIGN_IDENTITY = "Apple Distribution";
CODE_SIGN_STYLE = Manual;
PROVISIONING_PROFILE_SPECIFIER = "Donetick App Store(fastline)";
CURRENT_PROJECT_VERSION = 37;
DEVELOPMENT_TEAM = 6UJJ78R3BS;
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0;
MARKETING_VERSION = 1.2.16;
PRODUCT_BUNDLE_IDENTIFIER = com.donetick.app;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";

View File

@@ -4,5 +4,13 @@
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>TAG</string>
</array>
</dict>
</plist>

View File

@@ -1,6 +1,7 @@
import UIKit
import Capacitor
import FirebaseCore
import FirebaseMessaging
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
@@ -8,6 +9,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
return true
}
@@ -46,10 +48,17 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
NotificationCenter.default.post(name: .capacitorDidRegisterForRemoteNotifications, object: deviceToken)
Messaging.messaging().apnsToken = deviceToken
Messaging.messaging().token(completion: { (token, error) in
if let error = error {
NotificationCenter.default.post(name: .capacitorDidFailToRegisterForRemoteNotifications, object: error)
} else if let token = token {
NotificationCenter.default.post(name: .capacitorDidRegisterForRemoteNotifications, object: token)
}
})
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
NotificationCenter.default.post(name: .capacitorDidFailToRegisterForRemoteNotifications, object: error)
NotificationCenter.default.post(name: .capacitorDidFailToRegisterForRemoteNotifications, object: error)
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

@@ -1,14 +1,14 @@
{
"images" : [
"images": [
{
"filename" : "AppIcon-512@2x.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
"idiom": "universal",
"size": "1024x1024",
"filename": "AppIcon-512@2x.png",
"platform": "ios"
}
],
"info" : {
"author" : "xcode",
"version" : 1
"info": {
"author": "xcode",
"version": 1
}
}
}

View File

@@ -1,23 +1,56 @@
{
"images" : [
"images": [
{
"idiom" : "universal",
"filename" : "splash-2732x2732-2.png",
"scale" : "1x"
"idiom": "universal",
"filename": "Default@1x~universal~anyany.png",
"scale": "1x"
},
{
"idiom" : "universal",
"filename" : "splash-2732x2732-1.png",
"scale" : "2x"
"idiom": "universal",
"filename": "Default@2x~universal~anyany.png",
"scale": "2x"
},
{
"idiom" : "universal",
"filename" : "splash-2732x2732.png",
"scale" : "3x"
"idiom": "universal",
"filename": "Default@3x~universal~anyany.png",
"scale": "3x"
},
{
"appearances": [
{
"appearance": "luminosity",
"value": "dark"
}
],
"idiom": "universal",
"scale": "1x",
"filename": "Default@1x~universal~anyany-dark.png"
},
{
"appearances": [
{
"appearance": "luminosity",
"value": "dark"
}
],
"idiom": "universal",
"scale": "2x",
"filename": "Default@2x~universal~anyany-dark.png"
},
{
"appearances": [
{
"appearance": "luminosity",
"value": "dark"
}
],
"idiom": "universal",
"scale": "3x",
"filename": "Default@3x~universal~anyany-dark.png"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"info": {
"version": 1,
"author": "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

80
ios/App/App/Info.plist Normal file
View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NFCReaderUsageDescription</key>
<string>Donetick uses NFC to read and write chore tags for quick task completion.</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>Donetick</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>This app needs access to camera to take photos to attach to task or use as profile photo</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs access to photo library to select images to attach to task or use as profile photo</string>
<key>UIBackgroundModes</key>
<array/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.donetick.app</string>
<key>CFBundleURLSchemes</key>
<array>
<string>donetick</string>
</array>
</dict>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.682262497914-5dacpk46qcc1494lood6ch8ul9c83kop</string>
</array>
</dict>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>DoneTick Widget</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.widgetkit-extension</string>
</dict>
</dict>
</plist>

View File

@@ -1,6 +1,6 @@
require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
platform :ios, '13.0'
platform :ios, '15.0'
use_frameworks!
# workaround to avoid Xcode caching of Pods that requires
@@ -11,19 +11,29 @@ install! 'cocoapods', :disable_input_output_paths => true
def capacitor_pods
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorCommunitySqlite', :path => '../../node_modules/@capacitor-community/sqlite'
pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'
pod 'CapacitorBrowser', :path => '../../node_modules/@capacitor/browser'
pod 'CapacitorDevice', :path => '../../node_modules/@capacitor/device'
pod 'CapacitorLocalLlm', :path => '../../node_modules/@capacitor/local-llm'
pod 'CapacitorLocalNotifications', :path => '../../node_modules/@capacitor/local-notifications'
pod 'CapacitorNetwork', :path => '../../node_modules/@capacitor/network'
pod 'CapacitorPreferences', :path => '../../node_modules/@capacitor/preferences'
pod 'CapacitorPushNotifications', :path => '../../node_modules/@capacitor/push-notifications'
pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
pod 'CapgoCapacitorDocumentScanner', :path => '../../node_modules/@capgo/capacitor-document-scanner'
pod 'CapgoCapacitorNfc', :path => '../../node_modules/@capgo/capacitor-nfc'
pod 'CapgoCapacitorSocialLogin', :path => '../../node_modules/@capgo/capacitor-social-login'
pod 'JcesarmobileCapacitorOcr', :path => '../../node_modules/@jcesarmobile/capacitor-ocr'
pod 'RevenuecatPurchasesCapacitor', :path => '../../node_modules/@revenuecat/purchases-capacitor'
pod 'RevenuecatPurchasesCapacitorUi', :path => '../../node_modules/@revenuecat/purchases-capacitor-ui'
pod 'CapacitorPluginSafeArea', :path => '../../node_modules/capacitor-plugin-safe-area'
end
target 'App' do
capacitor_pods
# Add your Pods here
pod 'FirebaseMessaging' # Add this line
end
post_install do |installer|

View File

@@ -1,90 +1,171 @@
PODS:
- Alamofire (5.10.2)
- AppAuth (1.7.6):
- AppAuth/Core (= 1.7.6)
- AppAuth/ExternalUserAgent (= 1.7.6)
- AppAuth/Core (1.7.6)
- AppAuth/ExternalUserAgent (1.7.6):
- AppAuth (2.1.0):
- AppAuth/Core (= 2.1.0)
- AppAuth/ExternalUserAgent (= 2.1.0)
- AppAuth/Core (2.1.0)
- AppAuth/ExternalUserAgent (2.1.0):
- AppAuth/Core
- AppCheckCore (11.2.0):
- AppCheckCore (11.3.0):
- GoogleUtilities/Environment (~> 8.0)
- GoogleUtilities/UserDefaults (~> 8.0)
- PromisesObjC (~> 2.4)
- Capacitor (7.2.0):
- PromisesSwift (~> 2.4)
- RecaptchaInterop (~> 101.0)
- Capacitor (8.4.1):
- CapacitorCordova
- CapacitorApp (7.0.1):
- CapacitorApp (8.1.0):
- Capacitor
- CapacitorCommunitySqlite (7.0.0):
- CapacitorBrowser (8.0.3):
- Capacitor
- CapacitorCommunitySqlite (8.1.0):
- Capacitor
- SQLCipher
- ZIPFoundation
- CapacitorCordova (7.2.0)
- CapacitorDevice (7.0.1):
- CapacitorCordova (8.4.1)
- CapacitorDevice (8.0.2):
- Capacitor
- CapacitorLocalNotifications (7.0.1):
- CapacitorLocalLlm (1.0.0):
- Capacitor
- CapacitorNetwork (7.0.1):
- CapacitorLocalNotifications (8.2.0):
- Capacitor
- CapacitorPluginSafeArea (4.0.0):
- CapacitorNetwork (8.0.1):
- Capacitor
- CapacitorPreferences (7.0.1):
- CapacitorPluginSafeArea (5.0.1):
- Capacitor
- CapacitorPushNotifications (7.0.1):
- CapacitorPreferences (8.0.1):
- Capacitor
- CapacitorStatusBar (7.0.1):
- CapacitorPushNotifications (8.1.1):
- Capacitor
- CapgoCapacitorSocialLogin (7.5.3):
- CapacitorStatusBar (8.0.2):
- Capacitor
- CapgoCapacitorDocumentScanner (8.4.0):
- Capacitor
- CapgoCapacitorNfc (8.2.2):
- Capacitor
- CapgoCapacitorSocialLogin (8.3.36):
- Alamofire (~> 5.10.2)
- Capacitor
- FBSDKCoreKit (= 17.4.0)
- FBSDKLoginKit (= 17.4.0)
- GoogleSignIn (~> 8.0.0)
- FBAEMKit (17.4.0):
- FBSDKCoreKit_Basics (= 17.4.0)
- FBSDKCoreKit (17.4.0):
- FBAEMKit (= 17.4.0)
- FBSDKCoreKit_Basics (= 17.4.0)
- FBSDKCoreKit_Basics (17.4.0)
- FBSDKLoginKit (17.4.0):
- FBSDKCoreKit (= 17.4.0)
- GoogleSignIn (8.0.0):
- AppAuth (< 2.0, >= 1.7.3)
- FBSDKCoreKit (~> 18.0)
- FBSDKLoginKit (~> 18.0)
- GoogleSignIn (~> 9.0.0)
- FBAEMKit (18.1.0):
- FBSDKCoreKit_Basics (= 18.1.0)
- FBSDKCoreKit (18.1.0):
- FBAEMKit (= 18.1.0)
- FBSDKCoreKit_Basics (= 18.1.0)
- FBSDKCoreKit_Basics (18.1.0)
- FBSDKLoginKit (18.1.0):
- FBSDKCoreKit (= 18.1.0)
- FirebaseCore (12.15.0):
- FirebaseCoreInternal (~> 12.15.0)
- GoogleUtilities/Environment (~> 8.1)
- GoogleUtilities/Logger (~> 8.1)
- FirebaseCoreInternal (12.15.0):
- "GoogleUtilities/NSData+zlib (~> 8.1)"
- FirebaseInstallations (12.15.0):
- FirebaseCore (~> 12.15.0)
- GoogleUtilities/Environment (~> 8.1)
- GoogleUtilities/UserDefaults (~> 8.1)
- PromisesObjC (~> 2.4)
- FirebaseMessaging (12.15.0):
- FirebaseCore (~> 12.15.0)
- FirebaseInstallations (~> 12.15.0)
- GoogleDataTransport (~> 10.1)
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
- GoogleUtilities/Environment (~> 8.1)
- GoogleUtilities/Reachability (~> 8.1)
- GoogleUtilities/UserDefaults (~> 8.1)
- nanopb (~> 3.30910.0)
- GoogleDataTransport (10.1.0):
- nanopb (~> 3.30910.0)
- PromisesObjC (~> 2.4)
- GoogleSignIn (9.0.0):
- AppAuth (~> 2.0)
- AppCheckCore (~> 11.0)
- GTMAppAuth (< 5.0, >= 4.1.1)
- GTMAppAuth (~> 5.0)
- GTMSessionFetcher/Core (~> 3.3)
- GoogleUtilities/Environment (8.0.2):
- GoogleUtilities/AppDelegateSwizzler (8.1.2):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- GoogleUtilities/Privacy
- GoogleUtilities/Logger (8.0.2):
- GoogleUtilities/Environment (8.1.2):
- GoogleUtilities/Privacy
- GoogleUtilities/Logger (8.1.2):
- GoogleUtilities/Environment
- GoogleUtilities/Privacy
- GoogleUtilities/Privacy (8.0.2)
- GoogleUtilities/UserDefaults (8.0.2):
- GoogleUtilities/Network (8.1.2):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Privacy
- GoogleUtilities/Reachability
- "GoogleUtilities/NSData+zlib (8.1.2)":
- GoogleUtilities/Privacy
- GoogleUtilities/Privacy (8.1.2)
- GoogleUtilities/Reachability (8.1.2):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- GTMAppAuth (4.1.1):
- AppAuth/Core (~> 1.7)
- GoogleUtilities/UserDefaults (8.1.2):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- GTMAppAuth (5.0.0):
- AppAuth/Core (~> 2.0)
- GTMSessionFetcher/Core (< 4.0, >= 3.3)
- GTMSessionFetcher/Core (3.5.0)
- PromisesObjC (2.4.0)
- SQLCipher (4.7.0):
- SQLCipher/standard (= 4.7.0)
- SQLCipher/common (4.7.0)
- SQLCipher/standard (4.7.0):
- JcesarmobileCapacitorOcr (0.3.0):
- Capacitor
- nanopb (3.30910.0):
- nanopb/decode (= 3.30910.0)
- nanopb/encode (= 3.30910.0)
- nanopb/decode (3.30910.0)
- nanopb/encode (3.30910.0)
- PromisesObjC (2.4.1)
- PromisesSwift (2.4.1):
- PromisesObjC (= 2.4.1)
- PurchasesHybridCommon (17.55.1):
- RevenueCat (= 5.67.1)
- PurchasesHybridCommonUI (17.55.1):
- PurchasesHybridCommon (= 17.55.1)
- RevenueCatUI (= 5.67.1)
- RecaptchaInterop (101.0.0)
- RevenueCat (5.67.1)
- RevenuecatPurchasesCapacitor (12.3.2):
- Capacitor
- PurchasesHybridCommon (= 17.55.1)
- RevenuecatPurchasesCapacitorUi (12.3.2):
- Capacitor
- PurchasesHybridCommonUI (= 17.55.1)
- RevenueCatUI (5.67.1):
- RevenueCat (= 5.67.1)
- SQLCipher (4.10.0):
- SQLCipher/standard (= 4.10.0)
- SQLCipher/common (4.10.0)
- SQLCipher/standard (4.10.0):
- SQLCipher/common
- ZIPFoundation (0.9.19)
- ZIPFoundation (0.9.20)
DEPENDENCIES:
- "Capacitor (from `../../node_modules/@capacitor/ios`)"
- "CapacitorApp (from `../../node_modules/@capacitor/app`)"
- "CapacitorBrowser (from `../../node_modules/@capacitor/browser`)"
- "CapacitorCommunitySqlite (from `../../node_modules/@capacitor-community/sqlite`)"
- "CapacitorCordova (from `../../node_modules/@capacitor/ios`)"
- "CapacitorDevice (from `../../node_modules/@capacitor/device`)"
- "CapacitorLocalLlm (from `../../node_modules/@capacitor/local-llm`)"
- "CapacitorLocalNotifications (from `../../node_modules/@capacitor/local-notifications`)"
- "CapacitorNetwork (from `../../node_modules/@capacitor/network`)"
- CapacitorPluginSafeArea (from `../../node_modules/capacitor-plugin-safe-area`)
- "CapacitorPreferences (from `../../node_modules/@capacitor/preferences`)"
- "CapacitorPushNotifications (from `../../node_modules/@capacitor/push-notifications`)"
- "CapacitorStatusBar (from `../../node_modules/@capacitor/status-bar`)"
- "CapgoCapacitorDocumentScanner (from `../../node_modules/@capgo/capacitor-document-scanner`)"
- "CapgoCapacitorNfc (from `../../node_modules/@capgo/capacitor-nfc`)"
- "CapgoCapacitorSocialLogin (from `../../node_modules/@capgo/capacitor-social-login`)"
- FirebaseMessaging
- "JcesarmobileCapacitorOcr (from `../../node_modules/@jcesarmobile/capacitor-ocr`)"
- "RevenuecatPurchasesCapacitor (from `../../node_modules/@revenuecat/purchases-capacitor`)"
- "RevenuecatPurchasesCapacitorUi (from `../../node_modules/@revenuecat/purchases-capacitor-ui`)"
SPEC REPOS:
trunk:
@@ -95,11 +176,23 @@ SPEC REPOS:
- FBSDKCoreKit
- FBSDKCoreKit_Basics
- FBSDKLoginKit
- FirebaseCore
- FirebaseCoreInternal
- FirebaseInstallations
- FirebaseMessaging
- GoogleDataTransport
- GoogleSignIn
- GoogleUtilities
- GTMAppAuth
- GTMSessionFetcher
- nanopb
- PromisesObjC
- PromisesSwift
- PurchasesHybridCommon
- PurchasesHybridCommonUI
- RecaptchaInterop
- RevenueCat
- RevenueCatUI
- SQLCipher
- ZIPFoundation
@@ -108,10 +201,16 @@ EXTERNAL SOURCES:
:path: "../../node_modules/@capacitor/ios"
CapacitorApp:
:path: "../../node_modules/@capacitor/app"
CapacitorBrowser:
:path: "../../node_modules/@capacitor/browser"
CapacitorCommunitySqlite:
:path: "../../node_modules/@capacitor-community/sqlite"
CapacitorCordova:
:path: "../../node_modules/@capacitor/ios"
CapacitorDevice:
:path: "../../node_modules/@capacitor/device"
CapacitorLocalLlm:
:path: "../../node_modules/@capacitor/local-llm"
CapacitorLocalNotifications:
:path: "../../node_modules/@capacitor/local-notifications"
CapacitorNetwork:
@@ -124,37 +223,66 @@ EXTERNAL SOURCES:
:path: "../../node_modules/@capacitor/push-notifications"
CapacitorStatusBar:
:path: "../../node_modules/@capacitor/status-bar"
CapgoCapacitorDocumentScanner:
:path: "../../node_modules/@capgo/capacitor-document-scanner"
CapgoCapacitorNfc:
:path: "../../node_modules/@capgo/capacitor-nfc"
CapgoCapacitorSocialLogin:
:path: "../../node_modules/@capgo/capacitor-social-login"
JcesarmobileCapacitorOcr:
:path: "../../node_modules/@jcesarmobile/capacitor-ocr"
RevenuecatPurchasesCapacitor:
:path: "../../node_modules/@revenuecat/purchases-capacitor"
RevenuecatPurchasesCapacitorUi:
:path: "../../node_modules/@revenuecat/purchases-capacitor-ui"
SPEC CHECKSUMS:
Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
AppAuth: d4f13a8fe0baf391b2108511793e4b479691fb73
AppCheckCore: cc8fd0a3a230ddd401f326489c99990b013f0c4f
Capacitor: 03bc7cbdde6a629a8b910a9d7d78c3cc7ed09ea7
CapacitorApp: febecbb9582cb353aed037e18ec765141f880fe9
CapacitorCommunitySqlite: b11e556cf5d149f9e0b6fbbb47959a6cd718c3d0
CapacitorCordova: 5967b9ba03915ef1d585469d6e31f31dc49be96f
CapacitorDevice: c6f6d587dd310527f8a48bf09c4e7b4a4cf14329
CapacitorLocalNotifications: c2212755b33d2513b8bb325096ce3a64d4039ae3
CapacitorNetwork: 15cb4385f0913a8ceb5e9a4d7af1ec554bdb8de8
CapacitorPluginSafeArea: 22031c3436269ca80fac90ec2c94bc7c1e59a81d
CapacitorPreferences: 6c98117d4d7508034a4af9db64d6b26fc75d7b94
CapacitorPushNotifications: 6a2794788c583dd89215f1805ca4bced1b13dbdf
CapacitorStatusBar: 6e7af040d8fc4dd655999819625cae9c2d74c36f
CapgoCapacitorSocialLogin: 0daa087f32775c656fbfba09b8eae7c089b85ce2
FBAEMKit: 58cb5f302cdd715a56d4c1d0dfdd2e423ac1421a
FBSDKCoreKit: 94d7461d0cecf441b1ba7c41acfff41daa8ccd41
FBSDKCoreKit_Basics: 151b43db8b834d3f0e02f95d36a44ffd36265e45
FBSDKLoginKit: 5c1cd53c91a2282b3a4fe6e6d3dcf2b8b0d33d55
GoogleSignIn: ce8c89bb9b37fb624b92e7514cc67335d1e277e4
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de
AppAuth: ef4da5a3fc2e10b90c09a0a94a9baeaedc0341d5
AppCheckCore: 214137f5c378d1dec88a68425c467fe65aaff637
Capacitor: 35242afe195b1e53c58ca1b827d1b444c5e6602b
CapacitorApp: 449ffe26375e96f8aaaee625ac6e01e5c57c8650
CapacitorBrowser: c987c73d09d8bd3b5ec13f06338b1e14d5d2be69
CapacitorCommunitySqlite: eac6acfb852f46e7988fc59604d7f900498d354e
CapacitorCordova: eebe6bcf807b1b06f3f48237650f96bbcd0eef09
CapacitorDevice: 14cba6f88d1c3074cbf825fea977c8c526453ff8
CapacitorLocalLlm: a05516151a02923a9e7dae9949d3817e85e321f0
CapacitorLocalNotifications: 2615aa008f608b95d3921a778ee1988abf1e6148
CapacitorNetwork: 8812ce60d11fb63d8f2e4ba51a49b2e59892ebe2
CapacitorPluginSafeArea: 874619c00586248f1694210e72038123d422c2d9
CapacitorPreferences: cca2021f386efb75947c850334447d9ff22b14f1
CapacitorPushNotifications: ec08d589c226a2c0db7c032ec1bf5b044ec85f8e
CapacitorStatusBar: 01d5763b4ed720de5ce2edbc938de6a98f4c8f32
CapgoCapacitorDocumentScanner: 7ad9e8ed9c054d551bfc948660d995b9545723d8
CapgoCapacitorNfc: 8ea158143c441e1cf6d231a971e375511558d027
CapgoCapacitorSocialLogin: adffda2bec52a765bdaebf3fa9a6083bd9341d60
FBAEMKit: 64088ff0380f50e4a56e2ee07d984f7f1aef7595
FBSDKCoreKit: 8390ea3a8fac186f444275f31d7512e760b47cba
FBSDKCoreKit_Basics: 3a0005c78b355388bf2df5c6dbe6381b77ea4be3
FBSDKLoginKit: d8e2711a3a03b0026703735c8d28a2b5a0e1f4fd
FirebaseCore: 2e86a4ea1684d4381707069e4a6d89ac808e901e
FirebaseCoreInternal: 6ab6a02c94446c026d2cf35cf5383842ebaa4992
FirebaseInstallations: eb29ccbf64eaedf86fd5b2ccc7fabde567660b52
FirebaseMessaging: 40017d7bc8457ee295b0f41d480a80fdabc9994e
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleSignIn: c7f09cfbc85a1abf69187be091997c317cc33b77
GoogleUtilities: 766ace00c6b10d8148408f329d10c4f051931850
GTMAppAuth: 217a876b249c3c585a54fd6f73e6b58c4f5c4238
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
SQLCipher: ba9d0076041ed767c5bd3d3f77098318d04a403c
ZIPFoundation: b8c29ea7ae353b309bc810586181fd073cb3312c
JcesarmobileCapacitorOcr: d3668e104d7ad8968a9d00fd4766e18fea0fe305
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
PromisesObjC: 752c3227f599e3467650e47ea36f433eeb10c273
PromisesSwift: 217dea0fd5d2ad65222a109c48698add13cc1c5b
PurchasesHybridCommon: ecd9d7c586287625f1225b8de5e24c1021502270
PurchasesHybridCommonUI: 3056a3d261529f6adb8f74ecc3ab7f1cc0d3fab4
RecaptchaInterop: 11e0b637842dfb48308d242afc3f448062325aba
RevenueCat: 9357239a9f0978285e68983637b8a602e65c94f0
RevenuecatPurchasesCapacitor: c299be01b1a5c1d5eb118c30eadc84160944ecf2
RevenuecatPurchasesCapacitorUi: dc2ec0d97638ebe4ac0078452f5c212b1525ea1c
RevenueCatUI: 6f9291da540f98baf405b5bdfc46b2d5547b704a
SQLCipher: eb79c64049cb002b4e9fcb30edb7979bf4706dfc
ZIPFoundation: dfd3d681c4053ff7e2f7350bc4e53b5dba3f5351
PODFILE CHECKSUM: 54ec5ec72c1c5e3e8d03bd96cc1ec0deaf577d9e
PODFILE CHECKSUM: 21b805bdbbb6ac4b8a3527ee8ef346ba0a55ef65
COCOAPODS: 1.15.2
COCOAPODS: 1.16.2

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>85F4.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
</array>
<key>NSPrivacyCollectedDataTypes</key>
<array/>
</dict>
</plist>

0
ios/Podfile Normal file
View File

207
ios/Pods/Pods.xcodeproj/project.pbxproj generated Normal file
View File

@@ -0,0 +1,207 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXFileReference section */
9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
/* End PBXFileReference section */
/* Begin PBXGroup section */
93BAFDF14BA360977052E7B9CCC18E94 /* Products */ = {
isa = PBXGroup;
children = (
);
name = Products;
sourceTree = "<group>";
};
CF1408CF629C7361332E53B88F7BD30C = {
isa = PBXGroup;
children = (
9D940727FF8FB9C785EB98E56350EF41 /* Podfile */,
D89477F20FB1DE18A04690586D7808C4 /* Frameworks */,
93BAFDF14BA360977052E7B9CCC18E94 /* Products */,
);
sourceTree = "<group>";
};
D89477F20FB1DE18A04690586D7808C4 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXProject section */
BFDFE7DC352907FC980B868725387E98 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1600;
LastUpgradeCheck = 1600;
};
buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
Base,
en,
);
mainGroup = CF1408CF629C7361332E53B88F7BD30C;
minimizedProjectReferenceProxies = 0;
preferredProjectObjectVersion = 77;
productRefGroup = 93BAFDF14BA360977052E7B9CCC18E94 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
);
};
/* End PBXProject section */
/* Begin XCBuildConfiguration section */
2426522C419C0DE4525883EA7AABC025 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"POD_CONFIGURATION_RELEASE=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
STRIP_INSTALLED_PRODUCT = NO;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0;
SYMROOT = "${SRCROOT}/../build";
};
name = Release;
};
8F9FEBB7130A3DF8746ED9AA46FE33FA /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"POD_CONFIGURATION_DEBUG=1",
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
STRIP_INSTALLED_PRODUCT = NO;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
SYMROOT = "${SRCROOT}/../build";
};
name = Debug;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = {
isa = XCConfigurationList;
buildConfigurations = (
8F9FEBB7130A3DF8746ED9AA46FE33FA /* Debug */,
2426522C419C0DE4525883EA7AABC025 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = BFDFE7DC352907FC980B868725387E98 /* Project object */;
}

8105
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,12 @@
{
"name": "donetick",
"private": true,
"version": "0.1.99",
"version": "1.2.16",
"type": "module",
"engines": {
"node": ">=20.0.0",
"npm": ">=9.0.0"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
@@ -13,64 +17,102 @@
"start": "vite --host",
"dev": "vite",
"build": "vite build",
"build-selfhosted": "vite build --mode selfhosted",
"build-cf": "rm -rf package-lock.json && npm install && npm install --force @rollup/rollup-linux-x64-gnu@4.34.9 @swc/core-linux-x64-gnu && vite build",
"build-selfhosted": "rm -rf package-lock.json && npm install && npm install --force @rollup/rollup-linux-x64-gnu@4.34.9 @swc/core-linux-x64-gnu && vite build --mode selfhosted",
"build-win": "del package-lock.json && npm install && npm install --force @rollup/rollup-win32-x64-msvc @swc/core-win32-x64-msvc && vite build --mode selfhosted",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
"setup-m1": "rm -rf node_modules package-lock.json && npm install && npm install --force @rollup/rollup-darwin-arm64 @swc/core-darwin-arm64",
"setup-apple-silicon": "npm install --no-optional && npm install --force @rollup/rollup-darwin-arm64 @swc/core-darwin-arm64",
"test-cloudflare-build": "rm -rf node_modules package-lock.json && npm install && npm install --force @rollup/rollup-linux-x64-gnu@4.34.9 @swc/core-linux-x64-gnu && vite build",
"release": "npm version patch && npm run build && git push origin develop --tags",
"merge": "git checkout main && git merge develop && git push origin main && git checkout develop",
"ionic:build": "npm run build",
"ionic:serve": "npm run start"
"ionic:serve": "npm run start",
"android": "npm run build && npx cap sync android",
"android:dev": "npx cap run android --live-reload",
"cap": "npm run build && npx cap sync",
"bump": "node bump-version.js patch",
"bump:minor": "node bump-version.js minor",
"bump:major": "node bump-version.js major",
"bump:patch": "node bump-version.js patch"
},
"dependencies": {
"@capacitor-community/sqlite": "^6.0.2",
"@capacitor/android": "^6.1.1",
"@capacitor/app": "^6.0.0",
"@capacitor/cli": "^6.1.1",
"@capacitor/core": "^6.1.1",
"@capacitor/device": "^6.0.2",
"@capacitor/ios": "6.1.1",
"@capacitor/local-notifications": "^6.0.0",
"@capacitor/network": "^6.0.3",
"@capacitor/preferences": "^6.0.1",
"@capacitor/push-notifications": "^6.0.1",
"@codetrix-studio/capacitor-google-auth": "^3.4.0-rc.4",
"@capacitor-community/sqlite": "^8.0.0",
"@capacitor/android": "^8.0.0",
"@capacitor/app": "^8.0.0",
"@capacitor/browser": "^8.0.0",
"@capacitor/core": "^8.0.0",
"@capacitor/device": "^8.0.0",
"@capacitor/ios": "^8.0.0",
"@capacitor/local-llm": "^1.0.0",
"@capacitor/local-notifications": "^8.0.0",
"@capacitor/network": "^8.0.0",
"@capacitor/preferences": "^8.0.0",
"@capacitor/push-notifications": "^8.0.0",
"@capacitor/status-bar": "^8.0.0",
"@capgo/capacitor-document-scanner": "^8.4.0",
"@capgo/capacitor-nfc": "^8.0.0",
"@capgo/capacitor-social-login": "^8.0.0",
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.15.2",
"@hello-pangea/dnd": "^18.0.1",
"@jcesarmobile/capacitor-ocr": "^0.3.0",
"@meauxt/react-swipeable-list": "^1.0.0",
"@mui/icons-material": "^5.16.13",
"@mui/joy": "^5.0.0-beta.20",
"@mui/material": "^5.15.2",
"@openreplay/tracker": "^14.0.4",
"@revenuecat/purchases-capacitor": "^12.0.0",
"@revenuecat/purchases-capacitor-ui": "^12.0.0",
"@swc/core": "^1.12.5",
"@tanstack/react-query": "^5.17.0",
"aos": "^2.3.4",
"browser-image-compression": "^2.0.2",
"caniuse-lite": "^1.0.30001769",
"capacitor-plugin-safe-area": "^5.0.0",
"chrono-node": "^2.7.7",
"dotenv": "^16.4.5",
"esm": "^3.2.25",
"farmhash": "^4.0.1",
"event-source-polyfill": "^1.0.31",
"fuse.js": "^7.0.0",
"i18next": "^25.8.14",
"i18next-browser-languagedetector": "^8.2.1",
"i18next-http-backend": "^3.0.2",
"js-cookie": "^3.0.5",
"moment": "^2.30.1",
"murmurhash": "^2.0.1",
"prop-types": "^15.8.1",
"qrcode": "^1.5.4",
"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-i18next": "^16.5.6",
"react-router-dom": "^6.21.1",
"react-transition-group": "^4.4.5",
"reactjs-social-login": "^2.6.3",
"recharts": "^2.15.0",
"reusify": "^1.0.4",
"tesseract.js": "^7.0.0",
"vite-plugin-pwa": "^0.20.0"
},
"devDependencies": {
"@capacitor/assets": "^3.0.5",
"@capacitor/cli": "^8.0.0",
"@tanstack/eslint-plugin-query": "^5.14.6",
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
"@vite-pwa/assets-generator": "^0.2.4",
"@vitejs/plugin-react-swc": "^3.5.0",
"autoprefixer": "^10.4.16",
"baseline-browser-mapping": "^2.9.19",
"capacitor-set-version": "^2.2.0",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.2",
@@ -86,6 +128,10 @@
"prettier": "^3.1.1",
"prettier-plugin-tailwindcss": "^0.5.10",
"tailwindcss": "^3.4.0",
"typescript": "^5.8.0",
"vite": "^5.2.13"
},
"allowScripts": {
"tesseract.js@7.0.0": true
}
}

View File

@@ -0,0 +1,75 @@
{
"title": "المهام",
"myChores": "مهامي",
"allChores": "جميع المهام",
"addChore": "إضافة مهمة",
"editChore": "تعديل مهمة",
"deleteChore": "حذف مهمة",
"completeChore": "إكمال مهمة",
"dueDate": "تاريخ الاستحقاق",
"assignedTo": "مُسند إلى",
"priority": "الأولوية",
"status": "الحالة",
"description": "الوصف",
"choreView": {
"assignment": "التعيين",
"assigned": "المعين",
"last": "الأخير",
"schedule": "الجدول",
"due": "الاستحقاق",
"statistics": "الإحصائيات",
"completed": "مكتمل",
"times": "مرات",
"details": "التفاصيل",
"createdBy": "أنشئ بواسطة",
"na": "غير متوفر",
"taskCompleted": "المهمة مكتملة",
"taskCompletedMessage": "تم وضع علامة مكتملة على مهمتك",
"taskCompletionUndone": "تم التراجع عن إكمال المهمة.",
"taskSkipUndone": "تم التراجع عن تخطي المهمة.",
"undoSuccessful": "التراجع ناجح",
"undoFailed": "فشل التراجع",
"undoFailedMessage": "تعذر التراجع عن الإجراء. يرجى المحاولة مرة أخرى.",
"resetTimer": "إعادة تعيين المؤقت",
"resetTimerConfirmation": "هل أنت متأكد من أنك تريد إعادة تعيين المؤقت؟ سيؤدي هذا إلى مسح جميع سجلات الوقت منذ بدء المهمة.",
"clearAllTimeRecords": "مسح جميع سجلات الوقت",
"clearAllTimeConfirmation": "سيؤدي هذا إلى حذف جميع المؤقتات لهذه المهمة بشكل دائم وإعادتها إلى حالة \"لم تبدأ\".",
"descriptionTitle": "الوصف",
"description": "الوصف :",
"previousNote": "الملاحظة السابقة",
"previousNoteLabel": "الملاحظة السابقة:",
"subtasksLabel": "المهام الفرعية :",
"taskActions": "إجراءات المهمة",
"addNote": "أضف ملاحظة",
"additionalNotes": "ملاحظات إضافية:",
"notePlaceholder": "أضف ملاحظة حول الإكمال...",
"setCustomCompletionTime": "تعيين وقت إكمال مخصص",
"skipTask": "تخطي المهمة",
"skipTaskConfirmation": "هل أنت متأكد من أنك تريد تخطي هذه المهمة؟",
"markComplete": "وضع علامة مكتمل",
"markAsDone": "وضع علامة كمنجز",
"edit": "تعديل",
"archive": "أرشفة",
"unarchive": "إلغاء الأرشفة",
"viewHistory": "عرض السجل",
"history": "السجل",
"startTimer": "بدء المؤقت",
"start": "بدء",
"pauseTimer": "إيقاف المؤقت مؤقتاً",
"approve": "موافقة",
"reject": "رفض",
"pendingApproval": "في انتظار الموافقة",
"undo": "تراجع",
"skip": "تخطي",
"cancel": "إلغاء",
"noPriority": "بدون أولوية",
"subtasks": "المهام الفرعية",
"noDescription": "لا يوجد وصف متاح",
"timer": {
"active": "المؤقت نشط",
"paused": "المؤقت متوقف مؤقتاً",
"reset": "إعادة تعيين المؤقت",
"delete": "حذف الجلسة"
}
}
}

View File

@@ -0,0 +1,33 @@
{
"save": "حفظ",
"cancel": "إلغاء",
"delete": "حذف",
"edit": "تعديل",
"close": "إغلاق",
"confirm": "تأكيد",
"loading": "جارٍ التحميل...",
"error": "خطأ",
"success": "نجح",
"warning": "تحذير",
"refresh": "تحديث",
"copy": "نسخ",
"copied": "تم النسخ!",
"settings": "الإعدادات",
"yes": "نعم",
"no": "لا",
"back": "رجوع",
"backToCalendar": "العودة إلى التقويم",
"logout": "تسجيل الخروج",
"version": "النسخة",
"navigation": {
"allTasks": "جميع المهام",
"archived": "المؤرشفة",
"things": "الأشياء",
"labels": "التسميات",
"projects": "المشاريع",
"filters": "الفلاتر",
"activities": "الأنشطة",
"points": "النقاط",
"settings": "الإعدادات"
}
}

View File

@@ -0,0 +1,174 @@
{
"title": "الإعدادات",
"circleSettings": {
"title": "إعدادات الدائرة",
"description": "يتم ربط حسابك تلقائيًا بدائرة عند إنشاء واحدة أو الانضمام إليها. ادعُ الأصدقاء بسهولة من خلال مشاركة رمز الدائرة الفريد أو الرابط أدناه. ستتلقى إشعارًا أدناه عندما يطلب شخص ما الانضمام إلى دائرتك. إذا كنت ترغب في المغادرة، فما عليك سوى الضغط على زر 'مغادرة الدائرة'.",
"circleCode": "رمز الدائرة",
"copyCode": "نسخ الرمز",
"copyLink": "نسخ الرابط",
"codeCopied": "تم نسخ رمز الدائرة!",
"linkCopied": "تم نسخ الرابط!",
"joinCircle": "الانضمام إلى دائرة",
"joinCirclePlaceholder": "أدخل رمز الدائرة",
"join": "انضمام",
"leave": "مغادرة الدائرة",
"leaveConfirmTitle": "مغادرة الدائرة",
"leaveConfirmMessage": "هل أنت متأكد من أنك تريد مغادرة هذه الدائرة؟",
"circleMembers": "أعضاء الدائرة",
"circleMemberRequests": "طلبات انضمام الأعضاء",
"admin": "مشرف",
"member": "عضو",
"pending": "قيد الانتظار",
"accept": "قبول",
"reject": "رفض",
"makeAdmin": "جعله مشرف",
"makeMember": "جعله عضو",
"remove": "إزالة",
"webhookURL": "رابط Webhook",
"webhookDescription": "أدخل رابط webhook لتلقي إشعارات أحداث الدائرة",
"webhookPlaceholder": "https://your-webhook-url.com"
},
"accountSettings": {
"title": "إعدادات الحساب",
"subscription": "الاشتراك",
"subscriptionStatus": "الخطة الحالية",
"free": "مجاني",
"plus": "بلس",
"upgrade": "ترقية",
"cancel": "إلغاء",
"changePassword": "تغيير كلمة المرور",
"password": "كلمة المرور",
"dangerZone": "منطقة الخطر",
"dangerZoneDescription": "بمجرد حذف حسابك، لا يمكن التراجع. يرجى التأكد.",
"deleteAccount": "حذف الحساب"
},
"localization": {
"title": "التوطين",
"description": "تخصيص اللغة وتنسيق التاريخ والتفضيلات الإقليمية لحسابك.",
"language": "اللغة",
"languageDescription": "اختر لغتك المفضلة",
"dateFormat": "تنسيق التاريخ",
"dateFormatDescription": "اختر كيفية عرض التواريخ في التطبيق",
"timeFormat": "تنسيق الوقت",
"timeFormatDescription": "اختر تنسيق 12 أو 24 ساعة",
"12hour": "12 ساعة (ص/م)",
"24hour": "24 ساعة",
"firstDayOfWeek": "أول يوم في الأسبوع",
"firstDayOfWeekDescription": "اختر اليوم الذي يبدأ به أسبوعك",
"sunday": "الأحد",
"monday": "الاثنين",
"saturday": "السبت",
"formats": {
"mdy": "MM/DD/YYYY (الولايات المتحدة)",
"dmy": "DD/MM/YYYY (أوروبا)",
"ymd": "YYYY-MM-DD (ISO)",
"long": "تنسيق طويل (مثل 1 يناير 2024)",
"short": "تنسيق قصير (مثل 1 يناير 2024)"
}
},
"sidepanel": {
"title": "تخصيص اللوحة الجانبية",
"description": "قم بتخصيص تخطيط ورؤية البطاقات في اللوحة الجانبية. هذا القسم متاح فقط على أجهزة الشاشة الكبيرة مثل الأجهزة اللوحية وأجهزة سطح المكتب."
},
"theme": {
"title": "تفضيلات المظهر",
"description": "اختر كيف يبدو الموقع لك. حدد مظهرًا واحدًا أو قم بالمزامنة مع نظامك والتبديل تلقائيًا بين مظاهر النهار والليل.",
"themeMode": "وضع المظهر",
"light": "فاتح",
"dark": "داكن",
"system": "النظام"
},
"notifications": {
"settingsSaved": "تم حفظ الإعدادات بنجاح",
"settingsSaveFailed": "فشل حفظ الإعدادات",
"invalidWebhook": "رابط webhook غير صالح"
},
"profile": {
"title": "إعدادات الملف الشخصي",
"description": "تحديث اسم العرض وصورة الملف الشخصي.",
"photoUpdated": "تم تحديث الصورة",
"photoUpdatedMessage": "تم تحديث صورة ملفك الشخصي بنجاح!",
"uploadFailed": "فشل التحميل",
"uploadFailedMessage": "فشل تحميل صورتك. يرجى المحاولة مرة أخرى.",
"profileUpdated": "تم تحديث الملف الشخصي",
"profileUpdatedMessage": "تم حفظ معلومات ملفك الشخصي بنجاح!",
"updateFailed": "فشل التحديث",
"updateFailedMessage": "تعذر تحديث ملفك الشخصي. يرجى التحقق من اتصالك والمحاولة مرة أخرى.",
"changePhoto": "تغيير الصورة",
"displayName": "اسم العرض",
"displayNamePlaceholder": "أدخل اسم العرض الخاص بك",
"timezone": "المنطقة الزمنية",
"timezonePlaceholder": "اختر منطقتك الزمنية",
"save": "حفظ",
"cancel": "إلغاء"
},
"overview": {
"title": "الإعدادات",
"subtitle": "قم بتخصيص تجربتك وإدارة تفضيلات حسابك",
"upgrade": {
"title": "الترقية إلى بلس",
"description": "افتح ميزات قوية لتعزيز إنتاجيتك",
"button": "الترقية الآن",
"features": {
"richText": "أوصاف نصية منسقة",
"notifications": "إشعارات المهام",
"apiIntegrations": "تكاملات API",
"advancedAutomation": "أتمتة متقدمة"
}
},
"sections": {
"profile": {
"title": "إعدادات الملف الشخصي",
"description": "تحديث معلومات ملفك الشخصي والصورة واسم العرض وتفضيلات المنطقة الزمنية."
},
"circle": {
"title": "إعدادات الدائرة",
"description": "إدارة دائرتك ودعوة الأعضاء والتعامل مع طلبات الانضمام."
},
"account": {
"title": "إعدادات الحساب",
"description": "إدارة اشتراكك وتغيير كلمة المرور وخيارات حذف الحساب."
},
"subaccounts": {
"title": "الحسابات المُدارة",
"description": "إنشاء وإدارة حسابات فرعية لتسجيل الدخول وإكمال المهام المعينة."
},
"notifications": {
"title": "الإشعارات",
"description": "تكوين الإشعارات الفورية وتنبيهات البريد الإلكتروني ووجهات الإشعارات للمهام."
},
"mfa": {
"title": "المصادقة متعددة العوامل",
"description": "إضافة طبقة إضافية من الأمان باستخدام MFA مع تطبيقات المصادقة."
},
"apitokens": {
"title": "رموز API",
"description": "إنشاء وإدارة رموز الوصول لتكاملات الطرف الثالث والوصول إلى API."
},
"storage": {
"title": "إعدادات التخزين",
"description": "نسخ احتياطي واستعادة بياناتك وإدارة التخزين المحلي وتفضيلات المزامنة."
},
"sidepanel": {
"title": "تخصيص اللوحة الجانبية",
"description": "قم بتخصيص تخطيط ورؤية البطاقات في واجهة اللوحة الجانبية."
},
"theme": {
"title": "تفضيلات المظهر",
"description": "اختر مظهرك المفضل وقم بتكوين إعدادات الوضع الداكن/الفاتح."
},
"localization": {
"title": "التوطين",
"description": "تخصيص اللغة وتنسيق التاريخ وتنسيق الوقت والتفضيلات الإقليمية."
},
"advanced": {
"title": "الإعدادات المتقدمة",
"description": "تكوين webhooks والتحديثات في الوقت الفعلي وميزات متقدمة أخرى لتعزيز الإنتاجية."
},
"developer": {
"title": "إعدادات المطور",
"description": "عرض المعلومات الفنية حول رموز المصادقة واتصالات SSE وبيانات التصحيح."
}
}
}
}

View File

@@ -0,0 +1,75 @@
{
"title": "Aufgaben",
"myChores": "Meine Aufgaben",
"allChores": "Alle Aufgaben",
"addChore": "Aufgabe hinzufügen",
"editChore": "Aufgabe bearbeiten",
"deleteChore": "Aufgabe löschen",
"completeChore": "Aufgabe abschließen",
"dueDate": "Fälligkeitsdatum",
"assignedTo": "Zugewiesen an",
"priority": "Priorität",
"status": "Status",
"description": "Beschreibung",
"choreView": {
"assignment": "Zuweisung",
"assigned": "Zugewiesen",
"last": "Letzte",
"schedule": "Zeitplan",
"due": "Fällig",
"statistics": "Statistiken",
"completed": "Abgeschlossen",
"times": "mal",
"details": "Details",
"createdBy": "Erstellt von",
"na": "Nicht verfügbar",
"taskCompleted": "Aufgabe abgeschlossen",
"taskCompletedMessage": "Deine Aufgabe wurde als abgeschlossen markiert",
"taskCompletionUndone": "Aufgabenabschluss wurde rückgängig gemacht.",
"taskSkipUndone": "Aufgabe überspringen wurde rückgängig gemacht.",
"undoSuccessful": "Rückgängig erfolgreich",
"undoFailed": "Rückgängig fehlgeschlagen",
"undoFailedMessage": "Die Aktion konnte nicht rückgängig gemacht werden. Bitte versuche es erneut.",
"resetTimer": "Timer zurücksetzen",
"resetTimerConfirmation": "Bist du sicher, dass du den Timer zurücksetzen möchtest? Dies löscht alle Zeitaufzeichnungen seit du die Aufgabe gestartet hast.",
"clearAllTimeRecords": "Alle Zeitaufzeichnungen löschen",
"clearAllTimeConfirmation": "Dies löscht dauerhaft alle Timer für diese Aufgabe und setzt sie zurück auf \"nicht gestartet\".",
"descriptionTitle": "Beschreibung",
"description": "Beschreibung:",
"previousNote": "Vorherige Notiz",
"previousNoteLabel": "Vorherige Notiz:",
"subtasksLabel": "Unteraufgaben:",
"taskActions": "Aufgabenaktionen",
"addNote": "Notiz hinzufügen",
"additionalNotes": "Zusätzliche Notizen:",
"notePlaceholder": "Notiz zur Fertigstellung hinzufügen...",
"setCustomCompletionTime": "Benutzerdefinierte Abschlusszeit festlegen",
"skipTask": "Aufgabe überspringen",
"skipTaskConfirmation": "Bist du sicher, dass du diese Aufgabe überspringen möchtest?",
"markComplete": "Als abgeschlossen markieren",
"markAsDone": "Als erledigt markieren",
"edit": "Bearbeiten",
"archive": "Archivieren",
"unarchive": "Archivierung aufheben",
"viewHistory": "Verlauf anzeigen",
"history": "Verlauf",
"startTimer": "Timer starten",
"start": "Starten",
"pauseTimer": "Timer pausieren",
"approve": "Genehmigen",
"reject": "Ablehnen",
"pendingApproval": "Genehmigung ausstehend",
"undo": "Rückgängig",
"skip": "Überspringen",
"cancel": "Abbrechen",
"noPriority": "Keine Priorität",
"subtasks": "Unteraufgaben",
"noDescription": "Keine Beschreibung verfügbar",
"timer": {
"active": "Timer aktiv",
"paused": "Timer pausiert",
"reset": "Timer zurücksetzen",
"delete": "Sitzung löschen"
}
}
}

View File

@@ -0,0 +1,33 @@
{
"save": "Speichern",
"cancel": "Abbrechen",
"delete": "Löschen",
"edit": "Bearbeiten",
"close": "Schließen",
"confirm": "Bestätigen",
"loading": "Laden...",
"error": "Fehler",
"success": "Erfolg",
"warning": "Warnung",
"refresh": "Aktualisieren",
"copy": "Kopieren",
"copied": "Kopiert!",
"settings": "Einstellungen",
"yes": "Ja",
"no": "Nein",
"back": "Zurück",
"backToCalendar": "Zurück zum Kalender",
"logout": "Abmelden",
"version": "Version",
"navigation": {
"allTasks": "Alle Aufgaben",
"archived": "Archiviert",
"things": "Things",
"labels": "Beschriftungen",
"projects": "Projekte",
"filters": "Filter",
"activities": "Aktivitäten",
"points": "Punkte",
"settings": "Einstellungen"
}
}

View File

@@ -0,0 +1,174 @@
{
"title": "Einstellungen",
"circleSettings": {
"title": "Kreis-Einstellungen",
"description": "Dein Account wird automatisch mit einem Kreis verbunden, wenn du einen erstellst oder beitrittst. Lade einfach Freunde ein, indem du den einzigartigen Kreis-Code oder Link unten teilst. Du erhältst eine Benachrichtigung, wenn jemand deinem Kreis beitreten möchte. Wenn du gehen möchtest, klicke einfach auf 'Kreis verlassen'.",
"circleCode": "Kreis-Code",
"copyCode": "Code kopieren",
"copyLink": "Link kopieren",
"codeCopied": "Kreis-Code kopiert!",
"linkCopied": "Kreis-Link kopiert!",
"joinCircle": "Einem Kreis beitreten",
"joinCirclePlaceholder": "Kreis-Code eingeben",
"join": "Beitreten",
"leave": "Kreis verlassen",
"leaveConfirmTitle": "Kreis verlassen",
"leaveConfirmMessage": "Bist du sicher, dass du diesen Kreis verlassen möchtest?",
"circleMembers": "Kreis-Mitglieder",
"circleMemberRequests": "Kreis-Beitrittsanfragen",
"admin": "Administrator",
"member": "Mitglied",
"pending": "Ausstehend",
"accept": "Akzeptieren",
"reject": "Ablehnen",
"makeAdmin": "Zum Administrator machen",
"makeMember": "Zum Mitglied machen",
"remove": "Entfernen",
"webhookURL": "Webhook-URL",
"webhookDescription": "Gib eine Webhook-URL ein, um Benachrichtigungen für Kreis-Ereignisse zu erhalten",
"webhookPlaceholder": "https://deine-webhook-url.com"
},
"accountSettings": {
"title": "Account-Einstellungen",
"subscription": "Abonnement",
"subscriptionStatus": "Aktueller Plan",
"free": "Kostenlos",
"plus": "Plus",
"upgrade": "Upgraden",
"cancel": "Kündigen",
"changePassword": "Passwort ändern",
"password": "Passwort",
"dangerZone": "Gefahrenbereich",
"dangerZoneDescription": "Sobald du dein Konto löschst, gibt es kein Zurück mehr. Bitte sei dir sicher.",
"deleteAccount": "Account löschen"
},
"localization": {
"title": "Sprach- und Formateinstellungen",
"description": "Passe Sprache, Datumsformat und regionale Einstellungen für dein Konto an.",
"language": "Sprache",
"languageDescription": "Wähle deine bevorzugte Sprache",
"dateFormat": "Datumsformat",
"dateFormatDescription": "Wähle, wie Daten in der gesamten Anwendung angezeigt werden sollen",
"timeFormat": "Zeitformat",
"timeFormatDescription": "Wähle 12-Stunden- oder 24-Stunden-Zeitformat",
"12hour": "12-Stunden (AM/PM)",
"24hour": "24-Stunden",
"firstDayOfWeek": "Erster Tag der Woche",
"firstDayOfWeekDescription": "Wähle, welcher Tag deine Woche beginnt",
"sunday": "Sonntag",
"monday": "Montag",
"saturday": "Samstag",
"formats": {
"mdy": "MM/TT/JJJJ (USA)",
"dmy": "TT/MM/JJJJ (Europa)",
"ymd": "JJJJ-MM-TT (ISO)",
"long": "Langes Format (z.B. 1. Januar 2024)",
"short": "Kurzes Format (z.B. 1. Jan 2024)"
}
},
"sidepanel": {
"title": "Seitenleisten-Anpassung",
"description": "Passe das Layout und die Sichtbarkeit von Karten in der Seitenleiste an. Dieser Bereich ist nur auf großen Bildschirmgeräten wie Tablets und Desktops verfügbar."
},
"theme": {
"title": "Theme-Einstellungen",
"description": "Wähle, wie die Seite für dich aussieht. Wähle ein einzelnes Theme oder synchronisiere mit deinem System und wechsle automatisch zwischen Tag- und Nacht-Themes.",
"themeMode": "Theme-Modus",
"light": "Hell",
"dark": "Dunkel",
"system": "System"
},
"notifications": {
"settingsSaved": "Einstellungen erfolgreich gespeichert",
"settingsSaveFailed": "Speichern der Einstellungen fehlgeschlagen",
"invalidWebhook": "Ungültige Webhook-URL"
},
"profile": {
"title": "Profil-Einstellungen",
"description": "Aktualisiere deinen Anzeigenamen und dein Profilbild.",
"photoUpdated": "Foto aktualisiert",
"photoUpdatedMessage": "Dein Profilbild wurde erfolgreich aktualisiert!",
"uploadFailed": "Upload fehlgeschlagen",
"uploadFailedMessage": "Das Hochladen deines Fotos ist fehlgeschlagen. Bitte versuche es erneut.",
"profileUpdated": "Profil aktualisiert",
"profileUpdatedMessage": "Deine Profilinformationen wurden erfolgreich gespeichert!",
"updateFailed": "Update fehlgeschlagen",
"updateFailedMessage": "Dein Profil konnte nicht aktualisiert werden. Bitte überprüfe deine Verbindung und versuche es erneut.",
"changePhoto": "Foto ändern",
"displayName": "Anzeigename",
"displayNamePlaceholder": "Gib deinen Anzeigenamen ein",
"timezone": "Zeitzone",
"timezonePlaceholder": "Wähle deine Zeitzone",
"save": "Speichern",
"cancel": "Abbrechen"
},
"overview": {
"title": "Einstellungen",
"subtitle": "Passe deine Erfahrung an und verwalte deine Account-Einstellungen",
"upgrade": {
"title": "Auf Plus upgraden",
"description": "Schalte mächtige Funktionen frei, um deine Produktivität zu steigern",
"button": "Jetzt upgraden",
"features": {
"richText": "Rich-Text-Beschreibungen",
"notifications": "Aufgaben-Benachrichtigungen",
"apiIntegrations": "API-Integrationen",
"advancedAutomation": "Erweiterte Automatisierung"
}
},
"sections": {
"profile": {
"title": "Profil-Einstellungen",
"description": "Aktualisiere deine Profilinformationen, Foto, Anzeigenamen und Zeitzonen-Einstellungen."
},
"circle": {
"title": "Kreis-Einstellungen",
"description": "Verwalte deinen Kreis, lade Mitglieder ein und bearbeite Beitrittsanfragen."
},
"account": {
"title": "Account-Einstellungen",
"description": "Verwalte dein Abonnement, ändere dein Passwort und Account-Löschoptionen."
},
"subaccounts": {
"title": "Verwaltete Accounts",
"description": "Erstelle und verwalte Unter-Accounts zum Anmelden und Erledigen zugewiesener Aufgaben."
},
"notifications": {
"title": "Benachrichtigungen",
"description": "Konfiguriere Push-Benachrichtigungen, E-Mail-Benachrichtigungen und Benachrichtigungsziele für Aufgaben."
},
"mfa": {
"title": "Multi-Faktor-Authentifizierung",
"description": "Füge eine zusätzliche Sicherheitsebene mit MFA über Authenticator-Apps hinzu."
},
"apitokens": {
"title": "API-Token",
"description": "Generiere und verwalte Zugriffstoken für Drittanbieter-Integrationen und API-Zugang."
},
"storage": {
"title": "Speicher-Einstellungen",
"description": "Sichere und stelle deine Daten wieder her, verwalte lokalen Speicher und Synchronisierungseinstellungen."
},
"sidepanel": {
"title": "Seitenleisten-Anpassung",
"description": "Passe das Layout und die Sichtbarkeit von Karten in der Seitenleisten-Oberfläche an."
},
"theme": {
"title": "Theme-Einstellungen",
"description": "Wähle dein bevorzugtes Theme und konfiguriere Dunkel-/Hell-Modus-Einstellungen."
},
"localization": {
"title": "Sprach- und Formateinstellungen",
"description": "Passe Sprache, Datumsformat, Zeitformat und regionale Einstellungen an."
},
"advanced": {
"title": "Erweiterte Einstellungen",
"description": "Konfiguriere Webhooks, Echtzeit-Updates und andere erweiterte Funktionen für erhöhte Produktivität."
},
"developer": {
"title": "Entwickler-Einstellungen",
"description": "Zeige technische Informationen über Authentifizierungs-Token, SSE-Verbindungen und Debug-Daten an."
}
}
}
}

View File

@@ -0,0 +1,75 @@
{
"title": "Chores",
"myChores": "My Chores",
"allChores": "All Chores",
"addChore": "Add Chore",
"editChore": "Edit Chore",
"deleteChore": "Delete Chore",
"completeChore": "Complete Task",
"dueDate": "Due Date",
"assignedTo": "Assigned To",
"priority": "Priority",
"status": "Status",
"description": "Description",
"choreView": {
"assignment": "Assignment",
"assigned": "Assigned",
"last": "Last",
"schedule": "Schedule",
"due": "Due",
"statistics": "Statistics",
"completed": "Completed",
"times": "times",
"details": "Details",
"createdBy": "Created By",
"na": "N/A",
"taskCompleted": "Task Completed",
"taskCompletedMessage": "Your task has been marked as complete",
"taskCompletionUndone": "Task completion has been undone.",
"taskSkipUndone": "Task skip has been undone.",
"undoSuccessful": "Undo Successful",
"undoFailed": "Undo Failed",
"undoFailedMessage": "Unable to undo the action. Please try again.",
"resetTimer": "Reset Timer",
"resetTimerConfirmation": "Are you sure you want to reset the timer? This will clear all time records since you started the task.",
"clearAllTimeRecords": "Clear All Time Records",
"clearAllTimeConfirmation": "This will permanently delete all timers for this task and set it back to \"not started\".",
"descriptionTitle": "Description",
"description": "Description :",
"previousNote": "Previous Note",
"previousNoteLabel": "Previous note:",
"subtasksLabel": "Subtasks :",
"taskActions": "Task Actions",
"addNote": "Add a note",
"additionalNotes": "Additional Notes:",
"notePlaceholder": "Add a note about the completion...",
"setCustomCompletionTime": "Set custom completion time",
"skipTask": "Skip Task",
"skipTaskConfirmation": "Are you sure you want to skip this task?",
"markComplete": "Mark Complete",
"markAsDone": "Mark as done",
"edit": "Edit",
"archive": "Archive",
"unarchive": "Unarchive",
"viewHistory": "View History",
"history": "History",
"startTimer": "Start Timer",
"start": "Start",
"pauseTimer": "Pause Timer",
"approve": "Approve",
"reject": "Reject",
"pendingApproval": "Pending Approval",
"undo": "Undo",
"skip": "Skip",
"cancel": "Cancel",
"noPriority": "No Priority",
"subtasks": "Subtasks",
"noDescription": "No description available",
"timer": {
"active": "Timer Active",
"paused": "Timer Paused",
"reset": "Reset Timer",
"delete": "Delete Session"
}
}
}

View File

@@ -0,0 +1,33 @@
{
"save": "Save",
"cancel": "Cancel",
"delete": "Delete",
"edit": "Edit",
"close": "Close",
"confirm": "Confirm",
"loading": "Loading...",
"error": "Error",
"success": "Success",
"warning": "Warning",
"refresh": "Refresh",
"copy": "Copy",
"copied": "Copied!",
"settings": "Settings",
"yes": "Yes",
"no": "No",
"back": "Back",
"backToCalendar": "Back to Calendar",
"logout": "Logout",
"version": "Version",
"navigation": {
"allTasks": "All Tasks",
"archived": "Archived",
"things": "Things",
"labels": "Labels",
"projects": "Projects",
"filters": "Filters",
"activities": "Activities",
"points": "Points",
"settings": "Settings"
}
}

View File

@@ -0,0 +1,174 @@
{
"title": "Settings",
"circleSettings": {
"title": "Circle settings",
"description": "Your account is automatically connected to a Circle when you create or join one. Easily invite friends by sharing the unique Circle code or link below. You'll receive a notification below when someone requests to join your Circle. If you'd like to leave, simply hit the 'Leave Circle' button.",
"circleCode": "Circle Code",
"copyCode": "Copy Code",
"copyLink": "Copy Link",
"codeCopied": "Circle code copied!",
"linkCopied": "Circle link copied!",
"joinCircle": "Join a Circle",
"joinCirclePlaceholder": "Enter Circle Code",
"join": "Join",
"leave": "Leave Circle",
"leaveConfirmTitle": "Leave Circle",
"leaveConfirmMessage": "Are you sure you want to leave this circle?",
"circleMembers": "Circle Members",
"circleMemberRequests": "Circle Member Requests",
"admin": "Admin",
"member": "Member",
"pending": "Pending",
"accept": "Accept",
"reject": "Reject",
"makeAdmin": "Make Admin",
"makeMember": "Make Member",
"remove": "Remove",
"webhookURL": "Webhook URL",
"webhookDescription": "Enter a webhook URL to receive notifications for circle events",
"webhookPlaceholder": "https://your-webhook-url.com"
},
"accountSettings": {
"title": "Account Settings",
"subscription": "Subscription",
"subscriptionStatus": "Current Plan",
"free": "Free",
"plus": "Plus",
"upgrade": "Upgrade",
"cancel": "Cancel",
"changePassword": "Change Password",
"password": "Password",
"dangerZone": "Danger Zone",
"dangerZoneDescription": "Once you delete your account, there is no going back. Please be certain.",
"deleteAccount": "Delete Account"
},
"localization": {
"title": "Localization",
"description": "Customize language, date format, and regional preferences for your account.",
"language": "Language",
"languageDescription": "Select your preferred language",
"dateFormat": "Date Format",
"dateFormatDescription": "Choose how dates should be displayed throughout the application",
"timeFormat": "Time Format",
"timeFormatDescription": "Select 12-hour or 24-hour time format",
"12hour": "12-hour (AM/PM)",
"24hour": "24-hour",
"firstDayOfWeek": "First Day of Week",
"firstDayOfWeekDescription": "Select which day starts your week",
"sunday": "Sunday",
"monday": "Monday",
"saturday": "Saturday",
"formats": {
"mdy": "MM/DD/YYYY (US)",
"dmy": "DD/MM/YYYY (Europe)",
"ymd": "YYYY-MM-DD (ISO)",
"long": "Long format (e.g., January 1, 2024)",
"short": "Short format (e.g., Jan 1, 2024)"
}
},
"sidepanel": {
"title": "Sidepanel Customization",
"description": "Customize the layout and visibility of cards in the sidepanel. This section is only available on large screen devices such as tablets and desktops."
},
"theme": {
"title": "Theme preferences",
"description": "Choose how the site looks to you. Select a single theme, or sync with your system and automatically switch between day and night themes.",
"themeMode": "Theme mode",
"light": "Light",
"dark": "Dark",
"system": "System"
},
"notifications": {
"settingsSaved": "Settings saved successfully",
"settingsSaveFailed": "Failed to save settings",
"invalidWebhook": "Invalid webhook URL"
},
"profile": {
"title": "Profile Settings",
"description": "Update your display name and profile photo.",
"photoUpdated": "Photo Updated",
"photoUpdatedMessage": "Your profile photo has been updated successfully!",
"uploadFailed": "Upload Failed",
"uploadFailedMessage": "Failed to upload your photo. Please try again.",
"profileUpdated": "Profile Updated",
"profileUpdatedMessage": "Your profile information has been saved successfully!",
"updateFailed": "Update Failed",
"updateFailedMessage": "Unable to update your profile. Please check your connection and try again.",
"changePhoto": "Change Photo",
"displayName": "Display Name",
"displayNamePlaceholder": "Enter your display name",
"timezone": "Timezone",
"timezonePlaceholder": "Select your timezone",
"save": "Save",
"cancel": "Cancel"
},
"overview": {
"title": "Settings",
"subtitle": "Customize your experience and manage your account preferences",
"upgrade": {
"title": "Upgrade to Plus",
"description": "Unlock powerful features to enhance your productivity",
"button": "Upgrade Now",
"features": {
"richText": "Rich text descriptions",
"notifications": "Task notifications",
"apiIntegrations": "API integrations",
"advancedAutomation": "Advanced automation"
}
},
"sections": {
"profile": {
"title": "Profile Settings",
"description": "Update your profile information, photo, display name, and timezone preferences."
},
"circle": {
"title": "Circle Settings",
"description": "Manage your circle, invite members, and handle join requests."
},
"account": {
"title": "Account Settings",
"description": "Manage your subscription, change password, and account deletion options."
},
"subaccounts": {
"title": "Managed Accounts",
"description": "Create and manage sub accounts to log in and complete assigned tasks."
},
"notifications": {
"title": "Notifications",
"description": "Configure push notifications, email alerts, and notification targets for tasks."
},
"mfa": {
"title": "Multi-Factor Authentication",
"description": "Add an extra layer of security with MFA using authenticator apps."
},
"apitokens": {
"title": "API Tokens",
"description": "Generate and manage access tokens for third-party integrations and API access."
},
"storage": {
"title": "Storage Settings",
"description": "Backup and restore your data, manage local storage and sync preferences."
},
"sidepanel": {
"title": "Sidepanel Customization",
"description": "Customize the layout and visibility of cards in the sidepanel interface."
},
"theme": {
"title": "Theme Preferences",
"description": "Choose your preferred theme and configure dark/light mode settings."
},
"localization": {
"title": "Localization",
"description": "Customize language, date format, time format, and regional preferences."
},
"advanced": {
"title": "Advanced Settings",
"description": "Configure webhooks, real-time updates, and other advanced features for enhanced productivity."
},
"developer": {
"title": "Developer Settings",
"description": "View technical information about authentication tokens, SSE connections, and debug data."
}
}
}
}

View File

@@ -0,0 +1,75 @@
{
"title": "Tareas",
"myChores": "Mis Tareas",
"allChores": "Todas las Tareas",
"addChore": "Agregar Tarea",
"editChore": "Editar Tarea",
"deleteChore": "Eliminar Tarea",
"completeChore": "Completar Tarea",
"dueDate": "Fecha de Vencimiento",
"assignedTo": "Asignado a",
"priority": "Prioridad",
"status": "Estado",
"description": "Descripción",
"choreView": {
"assignment": "Asignación",
"assigned": "Asignado",
"last": "Último",
"schedule": "Horario",
"due": "Vencimiento",
"statistics": "Estadísticas",
"completed": "Completado",
"times": "veces",
"details": "Detalles",
"createdBy": "Creado por",
"na": "N/D",
"taskCompleted": "Tarea Completada",
"taskCompletedMessage": "Tu tarea ha sido marcada como completada",
"taskCompletionUndone": "La finalización de la tarea ha sido deshecha.",
"taskSkipUndone": "El salto de tarea ha sido deshecho.",
"undoSuccessful": "Deshacer Exitoso",
"undoFailed": "Deshacer Fallido",
"undoFailedMessage": "No se pudo deshacer la acción. Por favor, inténtalo de nuevo.",
"resetTimer": "Reiniciar Temporizador",
"resetTimerConfirmation": "¿Estás seguro de que quieres reiniciar el temporizador? Esto borrará todos los registros de tiempo desde que iniciaste la tarea.",
"clearAllTimeRecords": "Borrar Todos los Registros de Tiempo",
"clearAllTimeConfirmation": "Esto eliminará permanentemente todos los temporizadores de esta tarea y la volverá al estado \"no iniciada\".",
"descriptionTitle": "Descripción",
"description": "Descripción :",
"previousNote": "Nota Anterior",
"previousNoteLabel": "Nota anterior:",
"subtasksLabel": "Subtareas :",
"taskActions": "Acciones de Tarea",
"addNote": "Agregar una nota",
"additionalNotes": "Notas Adicionales:",
"notePlaceholder": "Agregar una nota sobre la finalización...",
"setCustomCompletionTime": "Establecer hora de finalización personalizada",
"skipTask": "Saltar Tarea",
"skipTaskConfirmation": "¿Estás seguro de que quieres saltar esta tarea?",
"markComplete": "Marcar como Completada",
"markAsDone": "Marcar como hecha",
"edit": "Editar",
"archive": "Archivar",
"unarchive": "Desarchivar",
"viewHistory": "Ver Historial",
"history": "Historial",
"startTimer": "Iniciar Temporizador",
"start": "Iniciar",
"pauseTimer": "Pausar Temporizador",
"approve": "Aprobar",
"reject": "Rechazar",
"pendingApproval": "Pendiente de Aprobación",
"undo": "Deshacer",
"skip": "Saltar",
"cancel": "Cancelar",
"noPriority": "Sin Prioridad",
"subtasks": "Subtareas",
"noDescription": "No hay descripción disponible",
"timer": {
"active": "Temporizador Activo",
"paused": "Temporizador Pausado",
"reset": "Reiniciar Temporizador",
"delete": "Eliminar Sesión"
}
}
}

View File

@@ -0,0 +1,33 @@
{
"save": "Guardar",
"cancel": "Cancelar",
"delete": "Eliminar",
"edit": "Editar",
"close": "Cerrar",
"confirm": "Confirmar",
"loading": "Cargando...",
"error": "Error",
"success": "Éxito",
"warning": "Advertencia",
"refresh": "Actualizar",
"copy": "Copiar",
"copied": "¡Copiado!",
"settings": "Configuración",
"yes": "Sí",
"no": "No",
"back": "Atrás",
"backToCalendar": "Volver al Calendario",
"logout": "Cerrar Sesión",
"version": "Versión",
"navigation": {
"allTasks": "Todas las Tareas",
"archived": "Archivadas",
"things": "Cosas",
"labels": "Etiquetas",
"projects": "Proyectos",
"filters": "Filtros",
"activities": "Actividades",
"points": "Puntos",
"settings": "Configuración"
}
}

View File

@@ -0,0 +1,174 @@
{
"title": "Configuración",
"circleSettings": {
"title": "Configuración del círculo",
"description": "Tu cuenta se conecta automáticamente a un Círculo cuando creas o te unes a uno. Invita fácilmente a amigos compartiendo el código único del Círculo o el enlace a continuación.",
"circleCode": "Código del Círculo",
"copyCode": "Copiar Código",
"copyLink": "Copiar Enlace",
"codeCopied": "¡Código del círculo copiado!",
"linkCopied": "¡Enlace copiado!",
"joinCircle": "Unirse a un Círculo",
"joinCirclePlaceholder": "Ingresa el Código del Círculo",
"join": "Unirse",
"leave": "Salir del Círculo",
"leaveConfirmTitle": "Salir del Círculo",
"leaveConfirmMessage": "¿Estás seguro de que quieres salir de este círculo?",
"circleMembers": "Miembros del Círculo",
"circleMemberRequests": "Solicitudes de Miembros del Círculo",
"admin": "Administrador",
"member": "Miembro",
"pending": "Pendiente",
"accept": "Aceptar",
"reject": "Rechazar",
"makeAdmin": "Hacer Administrador",
"makeMember": "Hacer Miembro",
"remove": "Eliminar",
"webhookURL": "URL del Webhook",
"webhookDescription": "Ingresa una URL de webhook para recibir notificaciones de eventos del círculo",
"webhookPlaceholder": "https://tu-url-webhook.com"
},
"accountSettings": {
"title": "Configuración de la Cuenta",
"subscription": "Suscripción",
"subscriptionStatus": "Plan Actual",
"free": "Gratis",
"plus": "Plus",
"upgrade": "Actualizar",
"cancel": "Cancelar",
"changePassword": "Cambiar Contraseña",
"password": "Contraseña",
"dangerZone": "Zona de Peligro",
"dangerZoneDescription": "Una vez que elimines tu cuenta, no hay vuelta atrás. Por favor, está seguro.",
"deleteAccount": "Eliminar Cuenta"
},
"localization": {
"title": "Localización",
"description": "Personaliza el idioma, formato de fecha y preferencias regionales para tu cuenta.",
"language": "Idioma",
"languageDescription": "Selecciona tu idioma preferido",
"dateFormat": "Formato de Fecha",
"dateFormatDescription": "Elige cómo se deben mostrar las fechas en toda la aplicación",
"timeFormat": "Formato de Hora",
"timeFormatDescription": "Selecciona formato de 12 o 24 horas",
"12hour": "12 horas (AM/PM)",
"24hour": "24 horas",
"firstDayOfWeek": "Primer Día de la Semana",
"firstDayOfWeekDescription": "Selecciona qué día comienza tu semana",
"sunday": "Domingo",
"monday": "Lunes",
"saturday": "Sábado",
"formats": {
"mdy": "MM/DD/AAAA (EE.UU.)",
"dmy": "DD/MM/AAAA (Europa)",
"ymd": "AAAA-MM-DD (ISO)",
"long": "Formato largo (ej., 1 de enero de 2024)",
"short": "Formato corto (ej., 1 ene 2024)"
}
},
"sidepanel": {
"title": "Personalización del Panel Lateral",
"description": "Personaliza el diseño y la visibilidad de las tarjetas en el panel lateral. Esta sección solo está disponible en dispositivos de pantalla grande como tabletas y computadoras de escritorio."
},
"theme": {
"title": "Preferencias de tema",
"description": "Elige cómo se ve el sitio para ti. Selecciona un solo tema o sincronízalo con tu sistema y cambia automáticamente entre temas de día y noche.",
"themeMode": "Modo de tema",
"light": "Claro",
"dark": "Oscuro",
"system": "Sistema"
},
"notifications": {
"settingsSaved": "Configuración guardada con éxito",
"settingsSaveFailed": "Error al guardar la configuración",
"invalidWebhook": "URL de webhook no válida"
},
"profile": {
"title": "Configuración del Perfil",
"description": "Actualiza tu nombre para mostrar y foto de perfil.",
"photoUpdated": "Foto Actualizada",
"photoUpdatedMessage": "¡Tu foto de perfil ha sido actualizada con éxito!",
"uploadFailed": "Error al Subir",
"uploadFailedMessage": "Error al subir tu foto. Por favor, inténtalo de nuevo.",
"profileUpdated": "Perfil Actualizado",
"profileUpdatedMessage": "¡Tu información de perfil ha sido guardada con éxito!",
"updateFailed": "Error al Actualizar",
"updateFailedMessage": "No se pudo actualizar tu perfil. Por favor, verifica tu conexión e inténtalo de nuevo.",
"changePhoto": "Cambiar Foto",
"displayName": "Nombre para Mostrar",
"displayNamePlaceholder": "Ingresa tu nombre para mostrar",
"timezone": "Zona Horaria",
"timezonePlaceholder": "Selecciona tu zona horaria",
"save": "Guardar",
"cancel": "Cancelar"
},
"overview": {
"title": "Configuración",
"subtitle": "Personaliza tu experiencia y administra las preferencias de tu cuenta",
"upgrade": {
"title": "Actualizar a Plus",
"description": "Desbloquea funciones potentes para mejorar tu productividad",
"button": "Actualizar Ahora",
"features": {
"richText": "Descripciones en texto enriquecido",
"notifications": "Notificaciones de tareas",
"apiIntegrations": "Integraciones API",
"advancedAutomation": "Automatización avanzada"
}
},
"sections": {
"profile": {
"title": "Configuración del Perfil",
"description": "Actualiza tu información de perfil, foto, nombre para mostrar y preferencias de zona horaria."
},
"circle": {
"title": "Configuración del Círculo",
"description": "Administra tu círculo, invita miembros y gestiona solicitudes de unión."
},
"account": {
"title": "Configuración de la Cuenta",
"description": "Administra tu suscripción, cambia la contraseña y opciones de eliminación de cuenta."
},
"subaccounts": {
"title": "Cuentas Administradas",
"description": "Crea y administra subcuentas para iniciar sesión y completar tareas asignadas."
},
"notifications": {
"title": "Notificaciones",
"description": "Configura notificaciones push, alertas por correo electrónico y destinos de notificación para tareas."
},
"mfa": {
"title": "Autenticación Multifactor",
"description": "Agrega una capa adicional de seguridad con MFA usando aplicaciones de autenticación."
},
"apitokens": {
"title": "Tokens API",
"description": "Genera y administra tokens de acceso para integraciones de terceros y acceso a la API."
},
"storage": {
"title": "Configuración de Almacenamiento",
"description": "Respalda y restaura tus datos, administra el almacenamiento local y las preferencias de sincronización."
},
"sidepanel": {
"title": "Personalización del Panel Lateral",
"description": "Personaliza el diseño y la visibilidad de las tarjetas en la interfaz del panel lateral."
},
"theme": {
"title": "Preferencias de Tema",
"description": "Elige tu tema preferido y configura los ajustes de modo oscuro/claro."
},
"localization": {
"title": "Localización",
"description": "Personaliza el idioma, formato de fecha, formato de hora y preferencias regionales."
},
"advanced": {
"title": "Configuración Avanzada",
"description": "Configura webhooks, actualizaciones en tiempo real y otras funciones avanzadas para mejorar la productividad."
},
"developer": {
"title": "Configuración de Desarrollador",
"description": "Ver información técnica sobre tokens de autenticación, conexiones SSE y datos de depuración."
}
}
}
}

View File

@@ -0,0 +1,75 @@
{
"title": "Tâches",
"myChores": "Mes Tâches",
"allChores": "Toutes les Tâches",
"addChore": "Ajouter une Tâche",
"editChore": "Modifier la Tâche",
"deleteChore": "Supprimer la Tâche",
"completeChore": "Terminer la Tâche",
"dueDate": "Date d'Échéance",
"assignedTo": "Assigné à",
"priority": "Priorité",
"status": "Statut",
"description": "Description",
"choreView": {
"assignment": "Attribution",
"assigned": "Assigné",
"last": "Dernier",
"schedule": "Calendrier",
"due": "Échéance",
"statistics": "Statistiques",
"completed": "Terminé",
"times": "fois",
"details": "Détails",
"createdBy": "Créé par",
"na": "N/A",
"taskCompleted": "Tâche Terminée",
"taskCompletedMessage": "Votre tâche a été marquée comme terminée",
"taskCompletionUndone": "La complétion de la tâche a été annulée.",
"taskSkipUndone": "Le saut de tâche a été annulé.",
"undoSuccessful": "Annulation Réussie",
"undoFailed": "Annulation Échouée",
"undoFailedMessage": "Impossible d'annuler l'action. Veuillez réessayer.",
"resetTimer": "Réinitialiser le Minuteur",
"resetTimerConfirmation": "Êtes-vous sûr de vouloir réinitialiser le minuteur ? Cela effacera tous les enregistrements de temps depuis le début de la tâche.",
"clearAllTimeRecords": "Effacer Tous les Enregistrements de Temps",
"clearAllTimeConfirmation": "Cela supprimera définitivement tous les minuteurs de cette tâche et la remettra à l'état \"non démarrée\".",
"descriptionTitle": "Description",
"description": "Description :",
"previousNote": "Note Précédente",
"previousNoteLabel": "Note précédente :",
"subtasksLabel": "Sous-tâches :",
"taskActions": "Actions de Tâche",
"addNote": "Ajouter une note",
"additionalNotes": "Notes Supplémentaires :",
"notePlaceholder": "Ajouter une note sur la complétion...",
"setCustomCompletionTime": "Définir une heure de complétion personnalisée",
"skipTask": "Passer la Tâche",
"skipTaskConfirmation": "Êtes-vous sûr de vouloir passer cette tâche ?",
"markComplete": "Marquer comme Terminée",
"markAsDone": "Marquer comme fait",
"edit": "Modifier",
"archive": "Archiver",
"unarchive": "Désarchiver",
"viewHistory": "Voir l'Historique",
"history": "Historique",
"startTimer": "Démarrer le Minuteur",
"start": "Démarrer",
"pauseTimer": "Mettre en Pause le Minuteur",
"approve": "Approuver",
"reject": "Rejeter",
"pendingApproval": "En Attente d'Approbation",
"undo": "Annuler",
"skip": "Passer",
"cancel": "Annuler",
"noPriority": "Aucune Priorité",
"subtasks": "Sous-tâches",
"noDescription": "Aucune description disponible",
"timer": {
"active": "Minuteur Actif",
"paused": "Minuteur en Pause",
"reset": "Réinitialiser le Minuteur",
"delete": "Supprimer la Session"
}
}
}

View File

@@ -0,0 +1,33 @@
{
"save": "Enregistrer",
"cancel": "Annuler",
"delete": "Supprimer",
"edit": "Modifier",
"close": "Fermer",
"confirm": "Confirmer",
"loading": "Chargement...",
"error": "Erreur",
"success": "Succès",
"warning": "Avertissement",
"refresh": "Actualiser",
"copy": "Copier",
"copied": "Copié !",
"settings": "Paramètres",
"yes": "Oui",
"no": "Non",
"back": "Retour",
"backToCalendar": "Retour au Calendrier",
"logout": "Déconnexion",
"version": "Version",
"navigation": {
"allTasks": "Toutes les Tâches",
"archived": "Archivées",
"things": "Objets",
"labels": "Étiquettes",
"projects": "Projets",
"filters": "Filtres",
"activities": "Activités",
"points": "Points",
"settings": "Paramètres"
}
}

View File

@@ -0,0 +1,174 @@
{
"title": "Paramètres",
"circleSettings": {
"title": "Paramètres du cercle",
"description": "Votre compte est automatiquement connecté à un Cercle lorsque vous en créez un ou en rejoignez un. Invitez facilement des amis en partageant le code unique du Cercle ou le lien ci-dessous.",
"circleCode": "Code du Cercle",
"copyCode": "Copier le Code",
"copyLink": "Copier le Lien",
"codeCopied": "Code du cercle copié !",
"linkCopied": "Lien copié !",
"joinCircle": "Rejoindre un Cercle",
"joinCirclePlaceholder": "Entrer le Code du Cercle",
"join": "Rejoindre",
"leave": "Quitter le Cercle",
"leaveConfirmTitle": "Quitter le Cercle",
"leaveConfirmMessage": "Êtes-vous sûr de vouloir quitter ce cercle ?",
"circleMembers": "Membres du Cercle",
"circleMemberRequests": "Demandes de Membres du Cercle",
"admin": "Administrateur",
"member": "Membre",
"pending": "En attente",
"accept": "Accepter",
"reject": "Rejeter",
"makeAdmin": "Nommer Administrateur",
"makeMember": "Nommer Membre",
"remove": "Supprimer",
"webhookURL": "URL du Webhook",
"webhookDescription": "Entrez une URL de webhook pour recevoir des notifications pour les événements du cercle",
"webhookPlaceholder": "https://votre-url-webhook.com"
},
"accountSettings": {
"title": "Paramètres du Compte",
"subscription": "Abonnement",
"subscriptionStatus": "Plan Actuel",
"free": "Gratuit",
"plus": "Plus",
"upgrade": "Mettre à Niveau",
"cancel": "Annuler",
"changePassword": "Changer le Mot de Passe",
"password": "Mot de passe",
"dangerZone": "Zone Dangereuse",
"dangerZoneDescription": "Une fois votre compte supprimé, il n'y a pas de retour en arrière. Veuillez être certain.",
"deleteAccount": "Supprimer le Compte"
},
"localization": {
"title": "Localisation",
"description": "Personnalisez la langue, le format de date et les préférences régionales pour votre compte.",
"language": "Langue",
"languageDescription": "Sélectionnez votre langue préférée",
"dateFormat": "Format de Date",
"dateFormatDescription": "Choisissez comment les dates doivent être affichées dans l'application",
"timeFormat": "Format de l'Heure",
"timeFormatDescription": "Sélectionnez le format 12 heures ou 24 heures",
"12hour": "12 heures (AM/PM)",
"24hour": "24 heures",
"firstDayOfWeek": "Premier Jour de la Semaine",
"firstDayOfWeekDescription": "Sélectionnez quel jour commence votre semaine",
"sunday": "Dimanche",
"monday": "Lundi",
"saturday": "Samedi",
"formats": {
"mdy": "MM/JJ/AAAA (États-Unis)",
"dmy": "JJ/MM/AAAA (Europe)",
"ymd": "AAAA-MM-JJ (ISO)",
"long": "Format long (ex., 1 janvier 2024)",
"short": "Format court (ex., 1 janv. 2024)"
}
},
"sidepanel": {
"title": "Personnalisation du Panneau Latéral",
"description": "Personnalisez la disposition et la visibilité des cartes dans le panneau latéral. Cette section n'est disponible que sur les grands écrans comme les tablettes et les ordinateurs de bureau."
},
"theme": {
"title": "Préférences de thème",
"description": "Choisissez comment le site vous apparaît. Sélectionnez un thème unique ou synchronisez avec votre système pour basculer automatiquement entre les thèmes jour et nuit.",
"themeMode": "Mode de thème",
"light": "Clair",
"dark": "Sombre",
"system": "Système"
},
"notifications": {
"settingsSaved": "Paramètres enregistrés avec succès",
"settingsSaveFailed": "Échec de l'enregistrement des paramètres",
"invalidWebhook": "URL de webhook invalide"
},
"profile": {
"title": "Paramètres du Profil",
"description": "Mettez à jour votre nom d'affichage et votre photo de profil.",
"photoUpdated": "Photo Mise à Jour",
"photoUpdatedMessage": "Votre photo de profil a été mise à jour avec succès !",
"uploadFailed": "Échec du Téléchargement",
"uploadFailedMessage": "Échec du téléchargement de votre photo. Veuillez réessayer.",
"profileUpdated": "Profil Mis à Jour",
"profileUpdatedMessage": "Vos informations de profil ont été enregistrées avec succès !",
"updateFailed": "Échec de la Mise à Jour",
"updateFailedMessage": "Impossible de mettre à jour votre profil. Veuillez vérifier votre connexion et réessayer.",
"changePhoto": "Changer la Photo",
"displayName": "Nom d'Affichage",
"displayNamePlaceholder": "Entrez votre nom d'affichage",
"timezone": "Fuseau Horaire",
"timezonePlaceholder": "Sélectionnez votre fuseau horaire",
"save": "Enregistrer",
"cancel": "Annuler"
},
"overview": {
"title": "Paramètres",
"subtitle": "Personnalisez votre expérience et gérez les préférences de votre compte",
"upgrade": {
"title": "Passer à Plus",
"description": "Débloquez des fonctionnalités puissantes pour améliorer votre productivité",
"button": "Mettre à Niveau Maintenant",
"features": {
"richText": "Descriptions en texte enrichi",
"notifications": "Notifications de tâches",
"apiIntegrations": "Intégrations API",
"advancedAutomation": "Automatisation avancée"
}
},
"sections": {
"profile": {
"title": "Paramètres du Profil",
"description": "Mettez à jour vos informations de profil, photo, nom d'affichage et préférences de fuseau horaire."
},
"circle": {
"title": "Paramètres du Cercle",
"description": "Gérez votre cercle, invitez des membres et gérez les demandes d'adhésion."
},
"account": {
"title": "Paramètres du Compte",
"description": "Gérez votre abonnement, changez le mot de passe et les options de suppression de compte."
},
"subaccounts": {
"title": "Comptes Gérés",
"description": "Créez et gérez des sous-comptes pour vous connecter et accomplir les tâches assignées."
},
"notifications": {
"title": "Notifications",
"description": "Configurez les notifications push, les alertes par e-mail et les cibles de notification pour les tâches."
},
"mfa": {
"title": "Authentification Multi-Facteurs",
"description": "Ajoutez une couche de sécurité supplémentaire avec MFA en utilisant des applications d'authentification."
},
"apitokens": {
"title": "Jetons API",
"description": "Générez et gérez des jetons d'accès pour les intégrations tierces et l'accès à l'API."
},
"storage": {
"title": "Paramètres de Stockage",
"description": "Sauvegardez et restaurez vos données, gérez le stockage local et les préférences de synchronisation."
},
"sidepanel": {
"title": "Personnalisation du Panneau Latéral",
"description": "Personnalisez la disposition et la visibilité des cartes dans l'interface du panneau latéral."
},
"theme": {
"title": "Préférences de Thème",
"description": "Choisissez votre thème préféré et configurez les paramètres de mode sombre/clair."
},
"localization": {
"title": "Localisation",
"description": "Personnalisez la langue, le format de date, le format de l'heure et les préférences régionales."
},
"advanced": {
"title": "Paramètres Avancés",
"description": "Configurez les webhooks, les mises à jour en temps réel et d'autres fonctionnalités avancées pour améliorer la productivité."
},
"developer": {
"title": "Paramètres Développeur",
"description": "Consultez les informations techniques sur les jetons d'authentification, les connexions SSE et les données de débogage."
}
}
}
}

View File

@@ -0,0 +1,75 @@
{
"title": "タスク",
"myChores": "自分のタスク",
"allChores": "すべてのタスク",
"addChore": "タスクを追加",
"editChore": "タスクを編集",
"deleteChore": "タスクを削除",
"completeChore": "タスクを完了",
"dueDate": "期限",
"assignedTo": "担当者",
"priority": "優先度",
"status": "ステータス",
"description": "説明",
"choreView": {
"assignment": "担当",
"assigned": "担当者",
"last": "前回",
"schedule": "スケジュール",
"due": "期限",
"statistics": "統計",
"completed": "完了",
"times": "回",
"details": "詳細",
"createdBy": "作成者",
"na": "該当なし",
"taskCompleted": "タスク完了",
"taskCompletedMessage": "タスクを完了としてマークしました",
"taskCompletionUndone": "タスクの完了を取り消しました。",
"taskSkipUndone": "タスクのスキップを取り消しました。",
"undoSuccessful": "取り消し成功",
"undoFailed": "取り消し失敗",
"undoFailedMessage": "操作を取り消せませんでした。もう一度お試しください。",
"resetTimer": "タイマーをリセット",
"resetTimerConfirmation": "本当にタイマーをリセットしますか?このタスクを開始してからのすべての時間記録が削除されます。",
"clearAllTimeRecords": "すべての時間記録を削除",
"clearAllTimeConfirmation": "このタスクのすべてのタイマーを完全に削除し、「未開始」の状態に戻します。",
"descriptionTitle": "説明",
"description": "説明 :",
"previousNote": "前回のメモ",
"previousNoteLabel": "前回のメモ:",
"subtasksLabel": "サブタスク :",
"taskActions": "タスク操作",
"addNote": "メモを追加",
"additionalNotes": "追加メモ:",
"notePlaceholder": "完了についてのメモを追加...",
"setCustomCompletionTime": "完了時刻をカスタム指定",
"skipTask": "タスクをスキップ",
"skipTaskConfirmation": "本当にこのタスクをスキップしますか?",
"markComplete": "完了としてマーク",
"markAsDone": "完了にする",
"edit": "編集",
"archive": "アーカイブ",
"unarchive": "アーカイブ解除",
"viewHistory": "履歴を表示",
"history": "履歴",
"startTimer": "タイマー開始",
"start": "開始",
"pauseTimer": "タイマー一時停止",
"approve": "承認",
"reject": "却下",
"pendingApproval": "承認待ち",
"undo": "取り消し",
"skip": "スキップ",
"cancel": "キャンセル",
"noPriority": "優先度なし",
"subtasks": "サブタスク",
"noDescription": "説明はありません",
"timer": {
"active": "タイマー動作中",
"paused": "タイマー一時停止中",
"reset": "タイマーをリセット",
"delete": "セッションを削除"
}
}
}

View File

@@ -0,0 +1,33 @@
{
"save": "保存",
"cancel": "キャンセル",
"delete": "削除",
"edit": "編集",
"close": "閉じる",
"confirm": "確認",
"loading": "読み込み中...",
"error": "エラー",
"success": "成功",
"warning": "警告",
"refresh": "更新",
"copy": "コピー",
"copied": "コピーしました!",
"settings": "設定",
"yes": "はい",
"no": "いいえ",
"back": "戻る",
"backToCalendar": "カレンダーに戻る",
"logout": "ログアウト",
"version": "バージョン",
"navigation": {
"allTasks": "すべてのタスク",
"archived": "アーカイブ済み",
"things": "Things",
"labels": "ラベル",
"projects": "プロジェクト",
"filters": "フィルター",
"activities": "アクティビティ",
"points": "ポイント",
"settings": "設定"
}
}

View File

@@ -0,0 +1,174 @@
{
"title": "設定",
"circleSettings": {
"title": "サークル設定",
"description": "アカウントは、サークルを作成または参加すると自動的にそのサークルに接続されます。下記のユニークなサークルコードまたはリンクを共有することで、友達を簡単に招待できます。誰かがサークルへの参加をリクエストした際は、下に通知が表示されます。サークルから脱退したい場合は、「サークルを脱退」ボタンを押してください。",
"circleCode": "サークルコード",
"copyCode": "コードをコピー",
"copyLink": "リンクをコピー",
"codeCopied": "サークルコードをコピーしました!",
"linkCopied": "サークルリンクをコピーしました!",
"joinCircle": "サークルに参加",
"joinCirclePlaceholder": "サークルコードを入力",
"join": "参加",
"leave": "サークルを脱退",
"leaveConfirmTitle": "サークルを脱退",
"leaveConfirmMessage": "本当にこのサークルから脱退しますか?",
"circleMembers": "サークルメンバー",
"circleMemberRequests": "サークル参加リクエスト",
"admin": "管理者",
"member": "メンバー",
"pending": "保留中",
"accept": "承認",
"reject": "拒否",
"makeAdmin": "管理者にする",
"makeMember": "メンバーにする",
"remove": "削除",
"webhookURL": "Webhook URL",
"webhookDescription": "サークルイベントの通知を受け取るための Webhook URL を入力してください",
"webhookPlaceholder": "https://your-webhook-url.com"
},
"accountSettings": {
"title": "アカウント設定",
"subscription": "サブスクリプション",
"subscriptionStatus": "現在のプラン",
"free": "無料",
"plus": "Plus",
"upgrade": "アップグレード",
"cancel": "キャンセル",
"changePassword": "パスワードを変更",
"password": "パスワード",
"dangerZone": "危険な操作",
"dangerZoneDescription": "アカウントを削除すると元に戻すことはできません。十分にご確認ください。",
"deleteAccount": "アカウントを削除"
},
"localization": {
"title": "地域設定",
"description": "言語、日付形式、地域の設定をカスタマイズします。",
"language": "言語",
"languageDescription": "使用する言語を選択してください",
"dateFormat": "日付形式",
"dateFormatDescription": "アプリケーション全体で日付をどのように表示するかを選択します",
"timeFormat": "時刻形式",
"timeFormatDescription": "12時間表記または24時間表記を選択します",
"12hour": "12時間 (AM/PM)",
"24hour": "24時間",
"firstDayOfWeek": "週の開始曜日",
"firstDayOfWeekDescription": "週の最初の曜日を選択します",
"sunday": "日曜日",
"monday": "月曜日",
"saturday": "土曜日",
"formats": {
"mdy": "MM/DD/YYYY (米国)",
"dmy": "DD/MM/YYYY (欧州)",
"ymd": "YYYY-MM-DD (ISO)",
"long": "長い形式 (例: January 1, 2024)",
"short": "短い形式 (例: Jan 1, 2024)"
}
},
"sidepanel": {
"title": "サイドパネルのカスタマイズ",
"description": "サイドパネル内のカードのレイアウトと表示をカスタマイズします。この機能はタブレットやデスクトップなど大画面のデバイスでのみ利用できます。"
},
"theme": {
"title": "テーマ設定",
"description": "サイトの見た目を選択します。単一のテーマを選ぶか、システム設定に同期して昼夜のテーマを自動で切り替えることができます。",
"themeMode": "テーマモード",
"light": "ライト",
"dark": "ダーク",
"system": "システム"
},
"notifications": {
"settingsSaved": "設定を保存しました",
"settingsSaveFailed": "設定の保存に失敗しました",
"invalidWebhook": "Webhook URL が無効です"
},
"profile": {
"title": "プロフィール設定",
"description": "表示名とプロフィール写真を更新します。",
"photoUpdated": "写真を更新しました",
"photoUpdatedMessage": "プロフィール写真が正常に更新されました!",
"uploadFailed": "アップロード失敗",
"uploadFailedMessage": "写真のアップロードに失敗しました。もう一度お試しください。",
"profileUpdated": "プロフィールを更新しました",
"profileUpdatedMessage": "プロフィール情報が正常に保存されました!",
"updateFailed": "更新失敗",
"updateFailedMessage": "プロフィールを更新できませんでした。接続を確認してから再度お試しください。",
"changePhoto": "写真を変更",
"displayName": "表示名",
"displayNamePlaceholder": "表示名を入力してください",
"timezone": "タイムゾーン",
"timezonePlaceholder": "タイムゾーンを選択してください",
"save": "保存",
"cancel": "キャンセル"
},
"overview": {
"title": "設定",
"subtitle": "体験をカスタマイズし、アカウント設定を管理します",
"upgrade": {
"title": "Plus へアップグレード",
"description": "強力な機能を解放して、生産性を向上させましょう",
"button": "今すぐアップグレード",
"features": {
"richText": "リッチテキストの説明",
"notifications": "タスク通知",
"apiIntegrations": "API 連携",
"advancedAutomation": "高度な自動化"
}
},
"sections": {
"profile": {
"title": "プロフィール設定",
"description": "プロフィール情報、写真、表示名、タイムゾーンを更新します。"
},
"circle": {
"title": "サークル設定",
"description": "サークルの管理、メンバーの招待、参加リクエストへの対応を行います。"
},
"account": {
"title": "アカウント設定",
"description": "サブスクリプションの管理、パスワード変更、アカウント削除を行います。"
},
"subaccounts": {
"title": "管理アカウント",
"description": "サブアカウントを作成・管理し、ログインや割り当てられたタスクの完了を行えるようにします。"
},
"notifications": {
"title": "通知",
"description": "プッシュ通知、メール通知、タスクの通知先を設定します。"
},
"mfa": {
"title": "多要素認証",
"description": "認証アプリを使った MFA でセキュリティをさらに強化します。"
},
"apitokens": {
"title": "API トークン",
"description": "サードパーティ連携や API アクセス用のトークンを生成・管理します。"
},
"storage": {
"title": "ストレージ設定",
"description": "データのバックアップと復元、ローカルストレージと同期の設定を管理します。"
},
"sidepanel": {
"title": "サイドパネルのカスタマイズ",
"description": "サイドパネルのカードのレイアウトと表示をカスタマイズします。"
},
"theme": {
"title": "テーマ設定",
"description": "好みのテーマを選択し、ダーク/ライトモードの設定を行います。"
},
"localization": {
"title": "地域設定",
"description": "言語、日付形式、時刻形式、地域の設定をカスタマイズします。"
},
"advanced": {
"title": "詳細設定",
"description": "Webhook、リアルタイム更新、その他の高度な機能を設定して生産性を高めます。"
},
"developer": {
"title": "開発者設定",
"description": "認証トークン、SSE 接続、デバッグデータなどの技術情報を確認できます。"
}
}
}
}

View File

@@ -0,0 +1,75 @@
{
"title": "Taken",
"myChores": "Mijn Taken",
"allChores": "Alle Taken",
"addChore": "Taak Toevoegen",
"editChore": "Taak Bewerken",
"deleteChore": "Taak Verwijderen",
"completeChore": "Taak Voltooien",
"dueDate": "Vervaldatum",
"assignedTo": "Toegewezen aan",
"priority": "Prioriteit",
"status": "Status",
"description": "Beschrijving",
"choreView": {
"assignment": "Toewijzing",
"assigned": "Toegewezen",
"last": "Laatste",
"schedule": "Schema",
"due": "Vervaldatum",
"statistics": "Statistieken",
"completed": "Voltooid",
"times": "keer",
"details": "Details",
"createdBy": "Aangemaakt door",
"na": "N/B",
"taskCompleted": "Taak Voltooid",
"taskCompletedMessage": "Uw taak is gemarkeerd als voltooid",
"taskCompletionUndone": "De voltooiing van de taak is ongedaan gemaakt.",
"taskSkipUndone": "Het overslaan van de taak is ongedaan gemaakt.",
"undoSuccessful": "Ongedaan Maken Geslaagd",
"undoFailed": "Ongedaan Maken Mislukt",
"undoFailedMessage": "Kan de actie niet ongedaan maken. Probeer het opnieuw.",
"resetTimer": "Timer Resetten",
"resetTimerConfirmation": "Weet u zeker dat u de timer wilt resetten? Dit wist alle tijdregistraties sinds u de taak bent begonnen.",
"clearAllTimeRecords": "Alle Tijdregistraties Wissen",
"clearAllTimeConfirmation": "Dit verwijdert permanent alle timers voor deze taak en zet hem terug naar \"niet gestart\".",
"descriptionTitle": "Beschrijving",
"description": "Beschrijving :",
"previousNote": "Vorige Notitie",
"previousNoteLabel": "Vorige notitie:",
"subtasksLabel": "Subtaken :",
"taskActions": "Taakacties",
"addNote": "Een notitie toevoegen",
"additionalNotes": "Aanvullende Notities:",
"notePlaceholder": "Voeg een notitie toe over de voltooiing...",
"setCustomCompletionTime": "Aangepaste voltooitijd instellen",
"skipTask": "Taak Overslaan",
"skipTaskConfirmation": "Weet u zeker dat u deze taak wilt overslaan?",
"markComplete": "Markeren als Voltooid",
"markAsDone": "Markeren als gedaan",
"edit": "Bewerken",
"archive": "Archiveren",
"unarchive": "Dearchiveren",
"viewHistory": "Geschiedenis Bekijken",
"history": "Geschiedenis",
"startTimer": "Timer Starten",
"start": "Starten",
"pauseTimer": "Timer Pauzeren",
"approve": "Goedkeuren",
"reject": "Afwijzen",
"pendingApproval": "In Afwachting van Goedkeuring",
"undo": "Ongedaan Maken",
"skip": "Overslaan",
"cancel": "Annuleren",
"noPriority": "Geen Prioriteit",
"subtasks": "Subtaken",
"noDescription": "Geen beschrijving beschikbaar",
"timer": {
"active": "Timer Actief",
"paused": "Timer Gepauzeerd",
"reset": "Timer Resetten",
"delete": "Sessie Verwijderen"
}
}
}

View File

@@ -0,0 +1,33 @@
{
"save": "Opslaan",
"cancel": "Annuleren",
"delete": "Verwijderen",
"edit": "Bewerken",
"close": "Sluiten",
"confirm": "Bevestigen",
"loading": "Laden...",
"error": "Fout",
"success": "Succes",
"warning": "Waarschuwing",
"refresh": "Vernieuwen",
"copy": "Kopiëren",
"copied": "Gekopieerd!",
"settings": "Instellingen",
"yes": "Ja",
"no": "Nee",
"back": "Terug",
"backToCalendar": "Terug naar Kalender",
"logout": "Uitloggen",
"version": "Versie",
"navigation": {
"allTasks": "Alle Taken",
"archived": "Gearchiveerd",
"things": "Dingen",
"labels": "Labels",
"projects": "Projecten",
"filters": "Filters",
"activities": "Activiteiten",
"points": "Punten",
"settings": "Instellingen"
}
}

View File

@@ -0,0 +1,174 @@
{
"title": "Instellingen",
"circleSettings": {
"title": "Cirkelinstellingen",
"description": "Uw account wordt automatisch verbonden met een Cirkel wanneer u er een aanmaakt of lid wordt. Nodig eenvoudig vrienden uit door de unieke Cirkelcode of onderstaande link te delen.",
"circleCode": "Cirkelcode",
"copyCode": "Code Kopiëren",
"copyLink": "Link Kopiëren",
"codeCopied": "Cirkelcode gekopieerd!",
"linkCopied": "Link gekopieerd!",
"joinCircle": "Lid Worden van een Cirkel",
"joinCirclePlaceholder": "Voer Cirkelcode in",
"join": "Lid Worden",
"leave": "Cirkel Verlaten",
"leaveConfirmTitle": "Cirkel Verlaten",
"leaveConfirmMessage": "Weet u zeker dat u deze cirkel wilt verlaten?",
"circleMembers": "Cirkelleden",
"circleMemberRequests": "Aanvragen voor Cirkellidmaatschap",
"admin": "Beheerder",
"member": "Lid",
"pending": "In behandeling",
"accept": "Accepteren",
"reject": "Afwijzen",
"makeAdmin": "Beheerder Maken",
"makeMember": "Lid Maken",
"remove": "Verwijderen",
"webhookURL": "Webhook URL",
"webhookDescription": "Voer een webhook URL in om meldingen te ontvangen voor cirkelgebeurtenissen",
"webhookPlaceholder": "https://uw-webhook-url.com"
},
"accountSettings": {
"title": "Accountinstellingen",
"subscription": "Abonnement",
"subscriptionStatus": "Huidig Plan",
"free": "Gratis",
"plus": "Plus",
"upgrade": "Upgraden",
"cancel": "Annuleren",
"changePassword": "Wachtwoord Wijzigen",
"password": "Wachtwoord",
"dangerZone": "Gevarenzone",
"dangerZoneDescription": "Zodra u uw account verwijdert, is er geen weg terug. Wees zeker van uw beslissing.",
"deleteAccount": "Account Verwijderen"
},
"localization": {
"title": "Lokalisatie",
"description": "Pas de taal, datumnotatie en regionale voorkeuren voor uw account aan.",
"language": "Taal",
"languageDescription": "Selecteer uw voorkeurstaal",
"dateFormat": "Datumnotatie",
"dateFormatDescription": "Kies hoe datums in de applicatie worden weergegeven",
"timeFormat": "Tijdnotatie",
"timeFormatDescription": "Selecteer 12-uurs of 24-uurs tijdnotatie",
"12hour": "12-uurs (AM/PM)",
"24hour": "24-uurs",
"firstDayOfWeek": "Eerste Dag van de Week",
"firstDayOfWeekDescription": "Selecteer welke dag uw week begint",
"sunday": "Zondag",
"monday": "Maandag",
"saturday": "Zaterdag",
"formats": {
"mdy": "MM/DD/JJJJ (VS)",
"dmy": "DD/MM/JJJJ (Europa)",
"ymd": "JJJJ-MM-DD (ISO)",
"long": "Lang formaat (bijv. 1 januari 2024)",
"short": "Kort formaat (bijv. 1 jan 2024)"
}
},
"sidepanel": {
"title": "Zijpaneel Aanpassen",
"description": "Pas de indeling en zichtbaarheid van kaarten in het zijpaneel aan. Deze sectie is alleen beschikbaar op grote schermapparaten zoals tablets en desktops."
},
"theme": {
"title": "Themavoorkeuren",
"description": "Kies hoe de site er voor u uitziet. Selecteer een enkel thema of synchroniseer met uw systeem en schakel automatisch tussen dag- en nachtthema's.",
"themeMode": "Thamamodus",
"light": "Licht",
"dark": "Donker",
"system": "Systeem"
},
"notifications": {
"settingsSaved": "Instellingen succesvol opgeslagen",
"settingsSaveFailed": "Opslaan van instellingen mislukt",
"invalidWebhook": "Ongeldige webhook URL"
},
"profile": {
"title": "Profielinstellingen",
"description": "Werk uw weergavenaam en profielfoto bij.",
"photoUpdated": "Foto Bijgewerkt",
"photoUpdatedMessage": "Uw profielfoto is succesvol bijgewerkt!",
"uploadFailed": "Uploaden Mislukt",
"uploadFailedMessage": "Het uploaden van uw foto is mislukt. Probeer het opnieuw.",
"profileUpdated": "Profiel Bijgewerkt",
"profileUpdatedMessage": "Uw profielgegevens zijn succesvol opgeslagen!",
"updateFailed": "Bijwerken Mislukt",
"updateFailedMessage": "Kan uw profiel niet bijwerken. Controleer uw verbinding en probeer het opnieuw.",
"changePhoto": "Foto Wijzigen",
"displayName": "Weergavenaam",
"displayNamePlaceholder": "Voer uw weergavenaam in",
"timezone": "Tijdzone",
"timezonePlaceholder": "Selecteer uw tijdzone",
"save": "Opslaan",
"cancel": "Annuleren"
},
"overview": {
"title": "Instellingen",
"subtitle": "Pas uw ervaring aan en beheer uw accountvoorkeuren",
"upgrade": {
"title": "Upgraden naar Plus",
"description": "Ontgrendel krachtige functies om uw productiviteit te verbeteren",
"button": "Nu Upgraden",
"features": {
"richText": "Rijke tekstbeschrijvingen",
"notifications": "Taakmeldingen",
"apiIntegrations": "API-integraties",
"advancedAutomation": "Geavanceerde automatisering"
}
},
"sections": {
"profile": {
"title": "Profielinstellingen",
"description": "Werk uw profielgegevens, foto, weergavenaam en tijdzonevoorkeuren bij."
},
"circle": {
"title": "Cirkelinstellingen",
"description": "Beheer uw cirkel, nodig leden uit en behandel lidmaatschapsverzoeken."
},
"account": {
"title": "Accountinstellingen",
"description": "Beheer uw abonnement, wijzig het wachtwoord en opties voor accountverwijdering."
},
"subaccounts": {
"title": "Beheerde Accounts",
"description": "Maak subaccounts aan en beheer ze om in te loggen en toegewezen taken te voltooien."
},
"notifications": {
"title": "Meldingen",
"description": "Configureer pushmeldingen, e-mailwaarschuwingen en meldingsdoelen voor taken."
},
"mfa": {
"title": "Multi-Factor Authenticatie",
"description": "Voeg een extra beveiligingslaag toe met MFA via authenticatie-apps."
},
"apitokens": {
"title": "API-tokens",
"description": "Genereer en beheer toegangstokens voor integraties van derden en API-toegang."
},
"storage": {
"title": "Opslaginstellingen",
"description": "Maak een back-up van uw gegevens en herstel ze, beheer lokale opslag en synchronisatievoorkeuren."
},
"sidepanel": {
"title": "Zijpaneel Aanpassen",
"description": "Pas de indeling en zichtbaarheid van kaarten in de zijpaneelinterface aan."
},
"theme": {
"title": "Themavoorkeuren",
"description": "Kies uw voorkeursthema en configureer de instellingen voor donker/licht modus."
},
"localization": {
"title": "Lokalisatie",
"description": "Pas de taal, datumnotatie, tijdnotatie en regionale voorkeuren aan."
},
"advanced": {
"title": "Geavanceerde Instellingen",
"description": "Configureer webhooks, real-time updates en andere geavanceerde functies voor verbeterde productiviteit."
},
"developer": {
"title": "Ontwikkelaarsinstellingen",
"description": "Bekijk technische informatie over authenticatietokens, SSE-verbindingen en foutopsporingsgegevens."
}
}
}
}

View File

@@ -0,0 +1,75 @@
{
"title": "Tarefas",
"myChores": "Minhas tarefas",
"allChores": "Todas as tarefas",
"addChore": "Adicionar tarefa",
"editChore": "Editar tarefa",
"deleteChore": "Excluir tarefa",
"completeChore": "Concluir tarefa",
"dueDate": "Data de vencimento",
"assignedTo": "Atribuída a",
"priority": "Prioridade",
"status": "Status",
"description": "Descrição",
"choreView": {
"assignment": "Atribuição",
"assigned": "Atribuída",
"last": "Última",
"schedule": "Agendamento",
"due": "Vence em",
"statistics": "Estatísticas",
"completed": "Concluída",
"times": "vezes",
"details": "Detalhes",
"createdBy": "Criada por",
"na": "N/D",
"taskCompleted": "Tarefa concluída",
"taskCompletedMessage": "Sua tarefa foi marcada como concluída",
"taskCompletionUndone": "A conclusão da tarefa foi desfeita.",
"taskSkipUndone": "O pulo da tarefa foi desfeito.",
"undoSuccessful": "Desfeito com sucesso",
"undoFailed": "Falha ao desfazer",
"undoFailedMessage": "Não foi possível desfazer a ação. Tente novamente.",
"resetTimer": "Reiniciar cronômetro",
"resetTimerConfirmation": "Tem certeza de que deseja reiniciar o cronômetro? Isso apagará todos os registros de tempo desde o início da tarefa.",
"clearAllTimeRecords": "Apagar todos os registros de tempo",
"clearAllTimeConfirmation": "Isso apagará permanentemente todos os cronômetros desta tarefa e a marcará como \"não iniciada\".",
"descriptionTitle": "Descrição",
"description": "Descrição :",
"previousNote": "Nota anterior",
"previousNoteLabel": "Nota anterior:",
"subtasksLabel": "Subtarefas :",
"taskActions": "Ações da tarefa",
"addNote": "Adicionar uma nota",
"additionalNotes": "Notas adicionais:",
"notePlaceholder": "Adicione uma nota sobre a conclusão...",
"setCustomCompletionTime": "Definir horário de conclusão personalizado",
"skipTask": "Pular tarefa",
"skipTaskConfirmation": "Tem certeza de que deseja pular esta tarefa?",
"markComplete": "Marcar como concluída",
"markAsDone": "Marcar como concluída",
"edit": "Editar",
"archive": "Arquivar",
"unarchive": "Desarquivar",
"viewHistory": "Ver histórico",
"history": "Histórico",
"startTimer": "Iniciar cronômetro",
"start": "Iniciar",
"pauseTimer": "Pausar cronômetro",
"approve": "Aprovar",
"reject": "Rejeitar",
"pendingApproval": "Aguardando aprovação",
"undo": "Desfazer",
"skip": "Pular",
"cancel": "Cancelar",
"noPriority": "Sem prioridade",
"subtasks": "Subtarefas",
"noDescription": "Nenhuma descrição disponível",
"timer": {
"active": "Cronômetro ativo",
"paused": "Cronômetro pausado",
"reset": "Reiniciar cronômetro",
"delete": "Excluir sessão"
}
}
}

View File

@@ -0,0 +1,33 @@
{
"save": "Salvar",
"cancel": "Cancelar",
"delete": "Excluir",
"edit": "Editar",
"close": "Fechar",
"confirm": "Confirmar",
"loading": "Carregando...",
"error": "Erro",
"success": "Sucesso",
"warning": "Aviso",
"refresh": "Atualizar",
"copy": "Copiar",
"copied": "Copiado!",
"settings": "Configurações",
"yes": "Sim",
"no": "Não",
"back": "Voltar",
"backToCalendar": "Voltar ao calendário",
"logout": "Sair",
"version": "Versão",
"navigation": {
"allTasks": "Todas as tarefas",
"archived": "Arquivadas",
"things": "Itens",
"labels": "Etiquetas",
"projects": "Projetos",
"filters": "Filtros",
"activities": "Atividades",
"points": "Pontos",
"settings": "Configurações"
}
}

View File

@@ -0,0 +1,174 @@
{
"title": "Configurações",
"circleSettings": {
"title": "Configurações do círculo",
"description": "Sua conta é conectada automaticamente a um círculo quando você cria ou entra em um. Convide amigos facilmente compartilhando o código ou link exclusivo do círculo abaixo. Você receberá uma notificação abaixo quando alguém solicitar entrar no seu círculo. Se quiser sair, basta clicar no botão \"Sair do círculo\".",
"circleCode": "Código do círculo",
"copyCode": "Copiar código",
"copyLink": "Copiar link",
"codeCopied": "Código do círculo copiado!",
"linkCopied": "Link do círculo copiado!",
"joinCircle": "Entrar em um círculo",
"joinCirclePlaceholder": "Digite o código do círculo",
"join": "Entrar",
"leave": "Sair do círculo",
"leaveConfirmTitle": "Sair do círculo",
"leaveConfirmMessage": "Tem certeza de que deseja sair deste círculo?",
"circleMembers": "Membros do círculo",
"circleMemberRequests": "Solicitações de entrada no círculo",
"admin": "Administrador",
"member": "Membro",
"pending": "Pendente",
"accept": "Aceitar",
"reject": "Rejeitar",
"makeAdmin": "Tornar administrador",
"makeMember": "Tornar membro",
"remove": "Remover",
"webhookURL": "URL do webhook",
"webhookDescription": "Digite uma URL de webhook para receber notificações de eventos do círculo",
"webhookPlaceholder": "https://sua-url-de-webhook.com"
},
"accountSettings": {
"title": "Configurações da conta",
"subscription": "Assinatura",
"subscriptionStatus": "Plano atual",
"free": "Gratuito",
"plus": "Plus",
"upgrade": "Fazer upgrade",
"cancel": "Cancelar",
"changePassword": "Alterar senha",
"password": "Senha",
"dangerZone": "Zona de perigo",
"dangerZoneDescription": "Após excluir sua conta, não há como voltar atrás. Tenha certeza antes de confirmar.",
"deleteAccount": "Excluir conta"
},
"localization": {
"title": "Localização",
"description": "Personalize idioma, formato de data e preferências regionais da sua conta.",
"language": "Idioma",
"languageDescription": "Selecione seu idioma preferido",
"dateFormat": "Formato de data",
"dateFormatDescription": "Escolha como as datas devem ser exibidas no aplicativo",
"timeFormat": "Formato de hora",
"timeFormatDescription": "Selecione o formato de 12 ou 24 horas",
"12hour": "12 horas (AM/PM)",
"24hour": "24 horas",
"firstDayOfWeek": "Primeiro dia da semana",
"firstDayOfWeekDescription": "Selecione com qual dia sua semana começa",
"sunday": "Domingo",
"monday": "Segunda-feira",
"saturday": "Sábado",
"formats": {
"mdy": "MM/DD/AAAA (EUA)",
"dmy": "DD/MM/AAAA (Europa)",
"ymd": "AAAA-MM-DD (ISO)",
"long": "Formato longo (ex.: 1 de janeiro de 2024)",
"short": "Formato curto (ex.: 1 de jan de 2024)"
}
},
"sidepanel": {
"title": "Personalização do painel lateral",
"description": "Personalize o layout e a visibilidade dos cartões no painel lateral. Esta seção está disponível apenas em dispositivos com telas grandes, como tablets e computadores."
},
"theme": {
"title": "Preferências de tema",
"description": "Escolha a aparência do site. Selecione um único tema ou sincronize com o sistema para alternar automaticamente entre os temas claro e escuro.",
"themeMode": "Modo do tema",
"light": "Claro",
"dark": "Escuro",
"system": "Sistema"
},
"notifications": {
"settingsSaved": "Configurações salvas com sucesso",
"settingsSaveFailed": "Falha ao salvar as configurações",
"invalidWebhook": "URL de webhook inválida"
},
"profile": {
"title": "Configurações do perfil",
"description": "Atualize seu nome de exibição e foto de perfil.",
"photoUpdated": "Foto atualizada",
"photoUpdatedMessage": "Sua foto de perfil foi atualizada com sucesso!",
"uploadFailed": "Falha no envio",
"uploadFailedMessage": "Falha ao enviar sua foto. Tente novamente.",
"profileUpdated": "Perfil atualizado",
"profileUpdatedMessage": "As informações do seu perfil foram salvas com sucesso!",
"updateFailed": "Falha na atualização",
"updateFailedMessage": "Não foi possível atualizar seu perfil. Verifique sua conexão e tente novamente.",
"changePhoto": "Alterar foto",
"displayName": "Nome de exibição",
"displayNamePlaceholder": "Digite seu nome de exibição",
"timezone": "Fuso horário",
"timezonePlaceholder": "Selecione seu fuso horário",
"save": "Salvar",
"cancel": "Cancelar"
},
"overview": {
"title": "Configurações",
"subtitle": "Personalize sua experiência e gerencie as preferências da sua conta",
"upgrade": {
"title": "Faça upgrade para o Plus",
"description": "Desbloqueie recursos poderosos para aumentar sua produtividade",
"button": "Fazer upgrade agora",
"features": {
"richText": "Descrições com texto formatado",
"notifications": "Notificações de tarefas",
"apiIntegrations": "Integrações de API",
"advancedAutomation": "Automação avançada"
}
},
"sections": {
"profile": {
"title": "Configurações do perfil",
"description": "Atualize as informações do seu perfil, foto, nome de exibição e preferências de fuso horário."
},
"circle": {
"title": "Configurações do círculo",
"description": "Gerencie seu círculo, convide membros e cuide das solicitações de entrada."
},
"account": {
"title": "Configurações da conta",
"description": "Gerencie sua assinatura, altere a senha e as opções de exclusão de conta."
},
"subaccounts": {
"title": "Contas gerenciadas",
"description": "Crie e gerencie subcontas para fazer login e concluir tarefas atribuídas."
},
"notifications": {
"title": "Notificações",
"description": "Configure notificações push, alertas por e-mail e destinos de notificação para tarefas."
},
"mfa": {
"title": "Autenticação multifator",
"description": "Adicione uma camada extra de segurança com MFA usando aplicativos autenticadores."
},
"apitokens": {
"title": "Tokens de API",
"description": "Gere e gerencie tokens de acesso para integrações de terceiros e acesso à API."
},
"storage": {
"title": "Configurações de armazenamento",
"description": "Faça backup e restauração dos seus dados, gerencie o armazenamento local e as preferências de sincronização."
},
"sidepanel": {
"title": "Personalização do painel lateral",
"description": "Personalize o layout e a visibilidade dos cartões na interface do painel lateral."
},
"theme": {
"title": "Preferências de tema",
"description": "Escolha seu tema preferido e configure o modo claro/escuro."
},
"localization": {
"title": "Localização",
"description": "Personalize idioma, formato de data, formato de hora e preferências regionais."
},
"advanced": {
"title": "Configurações avançadas",
"description": "Configure webhooks, atualizações em tempo real e outros recursos avançados para mais produtividade."
},
"developer": {
"title": "Configurações de desenvolvedor",
"description": "Veja informações técnicas sobre tokens de autenticação, conexões SSE e dados de depuração."
}
}
}
}

View File

@@ -0,0 +1,75 @@
{
"title": "家务",
"myChores": "我的家务",
"allChores": "所有家务",
"addChore": "添加家务",
"editChore": "编辑家务",
"deleteChore": "删除家务",
"completeChore": "完成任务",
"dueDate": "截止日期",
"assignedTo": "分配给",
"priority": "优先级",
"status": "状态",
"description": "描述",
"choreView": {
"assignment": "分配",
"assigned": "已分配",
"last": "上次",
"schedule": "日程",
"due": "截止",
"statistics": "统计",
"completed": "已完成",
"times": "次",
"details": "详情",
"createdBy": "创建者",
"na": "无",
"taskCompleted": "任务已完成",
"taskCompletedMessage": "您的任务已标记为完成",
"taskCompletionUndone": "任务完成已撤销。",
"taskSkipUndone": "任务跳过已撤销。",
"undoSuccessful": "撤销成功",
"undoFailed": "撤销失败",
"undoFailedMessage": "无法撤销该操作。请重试。",
"resetTimer": "重置计时器",
"resetTimerConfirmation": "您确定要重置计时器吗?这将清除自您开始任务以来的所有时间记录。",
"clearAllTimeRecords": "清除所有时间记录",
"clearAllTimeConfirmation": "这将永久删除此任务的所有计时器,并将其重置为“未开始”。",
"descriptionTitle": "描述",
"description": "描述:",
"previousNote": "上一条备注",
"previousNoteLabel": "上一条备注:",
"subtasksLabel": "子任务:",
"taskActions": "任务操作",
"addNote": "添加备注",
"additionalNotes": "附加备注:",
"notePlaceholder": "添加关于完成的备注...",
"setCustomCompletionTime": "设置自定义完成时间",
"skipTask": "跳过任务",
"skipTaskConfirmation": "您确定要跳过此任务吗?",
"markComplete": "标记完成",
"markAsDone": "标记为已完成",
"edit": "编辑",
"archive": "归档",
"unarchive": "取消归档",
"viewHistory": "查看历史",
"history": "历史",
"startTimer": "开始计时",
"start": "开始",
"pauseTimer": "暂停计时",
"approve": "批准",
"reject": "拒绝",
"pendingApproval": "待批准",
"undo": "撤销",
"skip": "跳过",
"cancel": "取消",
"noPriority": "无优先级",
"subtasks": "子任务",
"noDescription": "暂无描述",
"timer": {
"active": "计时中",
"paused": "已暂停",
"reset": "重置计时器",
"delete": "删除会话"
}
}
}

View File

@@ -0,0 +1,33 @@
{
"save": "保存",
"cancel": "取消",
"delete": "删除",
"edit": "编辑",
"close": "关闭",
"confirm": "确认",
"loading": "加载中...",
"error": "错误",
"success": "成功",
"warning": "警告",
"refresh": "刷新",
"copy": "复制",
"copied": "已复制!",
"settings": "设置",
"yes": "是",
"no": "否",
"back": "返回",
"backToCalendar": "返回日历",
"logout": "退出登录",
"version": "版本",
"navigation": {
"allTasks": "所有任务",
"archived": "已归档",
"things": "事项",
"labels": "标签",
"projects": "项目",
"filters": "筛选",
"activities": "活动",
"points": "积分",
"settings": "设置"
}
}

View File

@@ -0,0 +1,174 @@
{
"title": "设置",
"circleSettings": {
"title": "圈子设置",
"description": "当您创建或加入圈子时,您的账户会自动连接到该圈子。通过分享下方的唯一圈子代码或链接,即可轻松邀请好友。当有人请求加入您的圈子时,您会在下方收到通知。如果您想离开,只需点击“离开圈子”按钮。",
"circleCode": "圈子代码",
"copyCode": "复制代码",
"copyLink": "复制链接",
"codeCopied": "圈子代码已复制!",
"linkCopied": "圈子链接已复制!",
"joinCircle": "加入圈子",
"joinCirclePlaceholder": "输入圈子代码",
"join": "加入",
"leave": "离开圈子",
"leaveConfirmTitle": "离开圈子",
"leaveConfirmMessage": "您确定要离开此圈子吗?",
"circleMembers": "圈子成员",
"circleMemberRequests": "圈子成员申请",
"admin": "管理员",
"member": "成员",
"pending": "待处理",
"accept": "接受",
"reject": "拒绝",
"makeAdmin": "设为管理员",
"makeMember": "设为成员",
"remove": "移除",
"webhookURL": "Webhook URL",
"webhookDescription": "输入 Webhook URL 以接收圈子事件通知",
"webhookPlaceholder": "https://your-webhook-url.com"
},
"accountSettings": {
"title": "账户设置",
"subscription": "订阅",
"subscriptionStatus": "当前方案",
"free": "免费版",
"plus": "Plus 版",
"upgrade": "升级",
"cancel": "取消",
"changePassword": "修改密码",
"password": "密码",
"dangerZone": "危险区域",
"dangerZoneDescription": "一旦删除账户,将无法恢复。请谨慎操作。",
"deleteAccount": "删除账户"
},
"localization": {
"title": "本地化",
"description": "自定义您账户的语言、日期格式和区域偏好。",
"language": "语言",
"languageDescription": "选择您的首选语言",
"dateFormat": "日期格式",
"dateFormatDescription": "选择整个应用中日期的显示方式",
"timeFormat": "时间格式",
"timeFormatDescription": "选择 12 小时制或 24 小时制",
"12hour": "12 小时制 (AM/PM)",
"24hour": "24 小时制",
"firstDayOfWeek": "每周起始日",
"firstDayOfWeekDescription": "选择每周的第一天",
"sunday": "星期日",
"monday": "星期一",
"saturday": "星期六",
"formats": {
"mdy": "MM/DD/YYYY (美国)",
"dmy": "DD/MM/YYYY (欧洲)",
"ymd": "YYYY-MM-DD (ISO)",
"long": "长格式 (例如2024年1月1日)",
"short": "短格式 (例如2024年1月1日)"
}
},
"sidepanel": {
"title": "侧边栏自定义",
"description": "自定义侧边栏中卡片的布局和可见性。此部分仅适用于平板电脑和台式机等大屏设备。"
},
"theme": {
"title": "主题偏好",
"description": "选择网站的显示外观。您可以选择单一主题,或与系统同步,自动切换日间和夜间主题。",
"themeMode": "主题模式",
"light": "浅色",
"dark": "深色",
"system": "跟随系统"
},
"notifications": {
"settingsSaved": "设置保存成功",
"settingsSaveFailed": "设置保存失败",
"invalidWebhook": "无效的 Webhook URL"
},
"profile": {
"title": "个人资料设置",
"description": "更新您的显示名称和个人头像。",
"photoUpdated": "头像已更新",
"photoUpdatedMessage": "您的个人头像已成功更新!",
"uploadFailed": "上传失败",
"uploadFailedMessage": "头像上传失败。请重试。",
"profileUpdated": "资料已更新",
"profileUpdatedMessage": "您的个人资料已成功保存!",
"updateFailed": "更新失败",
"updateFailedMessage": "无法更新您的个人资料。请检查网络连接后重试。",
"changePhoto": "更换头像",
"displayName": "显示名称",
"displayNamePlaceholder": "输入您的显示名称",
"timezone": "时区",
"timezonePlaceholder": "选择您的时区",
"save": "保存",
"cancel": "取消"
},
"overview": {
"title": "设置",
"subtitle": "自定义您的体验并管理账户偏好",
"upgrade": {
"title": "升级到 Plus",
"description": "解锁强大功能,提升您的效率",
"button": "立即升级",
"features": {
"richText": "富文本描述",
"notifications": "任务通知",
"apiIntegrations": "API 集成",
"advancedAutomation": "高级自动化"
}
},
"sections": {
"profile": {
"title": "个人资料设置",
"description": "更新您的个人资料信息、头像、显示名称和时区偏好。"
},
"circle": {
"title": "圈子设置",
"description": "管理您的圈子、邀请成员并处理加入申请。"
},
"account": {
"title": "账户设置",
"description": "管理订阅、修改密码及账户删除选项。"
},
"subaccounts": {
"title": "托管账户",
"description": "创建和管理子账户,以便登录并完成分配的任务。"
},
"notifications": {
"title": "通知",
"description": "配置推送通知、邮件提醒及任务通知目标。"
},
"mfa": {
"title": "多因素认证",
"description": "使用身份验证器应用启用 MFA增加一层安全保障。"
},
"apitokens": {
"title": "API 令牌",
"description": "生成和管理用于第三方集成及 API 访问的访问令牌。"
},
"storage": {
"title": "存储设置",
"description": "备份和恢复数据,管理本地存储及同步偏好。"
},
"sidepanel": {
"title": "侧边栏自定义",
"description": "自定义侧边栏界面中卡片的布局和可见性。"
},
"theme": {
"title": "主题偏好",
"description": "选择您喜欢的主题并配置深色/浅色模式设置。"
},
"localization": {
"title": "本地化",
"description": "自定义语言、日期格式、时间格式及区域偏好。"
},
"advanced": {
"title": "高级设置",
"description": "配置 Webhook、实时更新及其他高级功能以提升效率。"
},
"developer": {
"title": "开发者设置",
"description": "查看有关身份验证令牌、SSE 连接及调试数据的技术信息。"
}
}
}
}

71
scripts/pull-secrets.sh Executable file
View File

@@ -0,0 +1,71 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
BW_SERVER="${BW_SERVER:-https://bitwarden.com}"
# ── Auth ──────────────────────────────────────────────────────────────────────
echo "→ Connecting to Vaultwarden at $BW_SERVER"
CURRENT_SERVER=$(bw status | jq -r '.serverUrl // empty')
if [ "$CURRENT_SERVER" != "$BW_SERVER" ]; then
bw logout || true
bw config server "$BW_SERVER"
fi
if [ -z "${BW_SESSION:-}" ]; then
BW_LOGIN_STATUS=$(bw status | jq -r '.status')
if [ "$BW_LOGIN_STATUS" = "unauthenticated" ]; then
if [ -n "${BW_CLIENTID:-}" ] && [ -n "${BW_CLIENTSECRET:-}" ]; then
bw login --apikey
else
bw login
fi
fi
export BW_SESSION=$(bw unlock --passwordenv BW_PASSWORD --raw)
fi
bw sync --session "$BW_SESSION" > /dev/null
# ── Helper ────────────────────────────────────────────────────────────────────
get_note() {
bw get item "$1" --session "$BW_SESSION" | jq -r '.notes'
}
get_password() {
bw get item "$1" --session "$BW_SESSION" | jq -r '.login.password // .notes'
}
# ── Android ───────────────────────────────────────────────────────────────────
echo "→ Writing android/app/google-services.json"
get_note "Donetick Google Services Android" > "$REPO_ROOT/android/app/google-services.json"
echo "→ Writing android keystore"
get_note "Donetick Android Keystore" | base64 --decode > "$REPO_ROOT/android/app/release/donetick.jks"
KEYSTORE_PASSWORD=$(get_password "Donetick Keystore Password")
cat > "$REPO_ROOT/android/keystore.properties" <<EOF
storeFile=release/donetick.jks
storePassword=$KEYSTORE_PASSWORD
keyAlias=key0
keyPassword=$KEYSTORE_PASSWORD
EOF
echo "→ Writing android/play-service-account.json"
get_note "Donetick Google Play Service Account" > "$REPO_ROOT/android/play-service-account.json"
# ── iOS ───────────────────────────────────────────────────────────────────────
echo "→ Writing ios/App/App/GoogleService-Info.plist"
get_note "Donetick Google Services iOS" > "$REPO_ROOT/ios/App/App/GoogleService-Info.plist"
echo "→ Writing App Store Connect key"
get_note "Donetick App Store Connect Key" | base64 --decode > "$REPO_ROOT/ios/AuthKey_84F695CDQ3.p8"
# ── Env ───────────────────────────────────────────────────────────────────────
echo "→ Writing .env.production"
get_note "Donetick Env Production" > "$REPO_ROOT/.env.production"
echo "✓ All secrets pulled successfully"

69
scripts/push-secrets.sh Executable file
View File

@@ -0,0 +1,69 @@
#!/usr/bin/env bash
# One-time script to upload local secrets into Vaultwarden.
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
# BW_SERVER="${BW_SERVER:-https://www.bitwareden.com}"
# ── Auth ──────────────────────────────────────────────────────────────────────
# bw config server "$BW_SERVER"
# bw login
export BW_SESSION=$(bw unlock --passwordenv BW_PASSWORD --raw)
# ── Helper ────────────────────────────────────────────────────────────────────
upsert_secure_note() {
local name="$1"
local content="$2"
local existing_id
existing_id=$(bw list items --session "$BW_SESSION" | jq -r --arg n "$name" '.[] | select(.name == $n) | .id' | head -1)
if [[ -n "$existing_id" ]]; then
bw get item "$existing_id" --session "$BW_SESSION" \
| jq --arg c "$content" '.notes = $c' \
| bw encode \
| bw edit item "$existing_id" --session "$BW_SESSION" > /dev/null
echo " ✓ Updated: $name"
else
bw get template item --session "$BW_SESSION" \
| jq --arg n "$name" --arg c "$content" \
'.name = $n | .type = 2 | .secureNote = {"type":0} | .notes = $c' \
| bw encode \
| bw create item --session "$BW_SESSION" > /dev/null
echo " ✓ Created: $name"
fi
}
# ── Upload ────────────────────────────────────────────────────────────────────
echo "→ Uploading Android google-services.json"
upsert_secure_note \
"Donetick Google Services Android" \
"$(cat "$REPO_ROOT/android/app/google-services.json")"
echo "→ Uploading Fastline google-services.json"
upsert_secure_note \
"Donetick Google Play Service Account" \
"$(cat "$REPO_ROOT/donetick-5f910-5688a280a65a--fastline.json")"
echo "→ Uploading Android keystore (base64)"
upsert_secure_note \
"Donetick Android Keystore" \
"$(base64 < /Users/mohamad-macbook-air/donetick-android-ley)"
echo "→ Uploading iOS GoogleService-Info.plist"
upsert_secure_note \
"Donetick Google Services iOS" \
"$(cat "$REPO_ROOT/ios/App/App/GoogleService-Info.plist")"
echo "→ Uploading App Store Connect key (base64)"
upsert_secure_note \
"Donetick App Store Connect Key" \
"$(base64 < /Users/mohamad-macbook-air/Downloads/AuthKey_84F695CDQ3.p8)"
echo "→ Uploading .env.production"
upsert_secure_note \
"Donetick Env Production" \
"$(cat "$REPO_ROOT/.env.production")"
echo ""
echo "✓ All secrets uploaded. Verify in Vaultwarden, then you can safely delete local copies outside the repo."
echo " NOTE: 'Donetick Keystore Password' should already exist — if not, create it manually as a Login item."

98
scripts/release.sh Executable file
View File

@@ -0,0 +1,98 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$REPO_ROOT"
PLATFORM="both"
BUMP="patch"
SKIP_BUMP=false
UPLOAD=false
ANDROID_TRACK="internal"
usage() {
cat <<EOF
Usage: $(basename "$0") [--android|--ios] [--bump patch|minor|major] [--skip-bump] [--upload] [--track TRACK]
Builds signed release artifacts for Android (.aab) and/or iOS (.ipa).
--android Build Android only
--ios Build iOS only
--bump TYPE Version bump type before building (default: patch)
--skip-bump Don't bump the version, build with the current one
--upload Also upload: Android to Play Store, iOS to TestFlight
--track TRACK Play Store track for --upload (default: internal)
-h, --help Show this help
Requires:
- scripts/pull-secrets.sh to have been run (keystore, google-services, App Store Connect key, Play service account)
- ASC_ISSUER_ID env var set (App Store Connect API key issuer id) for iOS builds/uploads
- bundle install (fastlane) run at least once
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--android) PLATFORM="android"; shift ;;
--ios) PLATFORM="ios"; shift ;;
--bump) BUMP="$2"; shift 2 ;;
--skip-bump) SKIP_BUMP=true; shift ;;
--upload) UPLOAD=true; shift ;;
--track) ANDROID_TRACK="$2"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown option: $1" >&2; usage; exit 1 ;;
esac
done
if [ -f "$REPO_ROOT/.env.production" ]; then
set -a
# shellcheck disable=SC1091
source "$REPO_ROOT/.env.production"
set +a
fi
if [ "$SKIP_BUMP" = false ]; then
echo "→ Bumping version ($BUMP)"
node bump-version.js "$BUMP"
fi
echo "→ Building web assets"
npm run build
echo "→ Syncing Capacitor"
npx cap sync
if [ -f Gemfile ] && command -v bundle >/dev/null 2>&1; then
RUN="bundle exec fastlane"
else
RUN="fastlane"
fi
if [ "$PLATFORM" = "android" ] || [ "$PLATFORM" = "both" ]; then
echo "→ Building signed Android release (.aab)"
$RUN android release
if [ "$UPLOAD" = true ]; then
echo "→ Uploading Android release to Play Store ($ANDROID_TRACK track)"
$RUN android upload track:"$ANDROID_TRACK"
fi
fi
if [ "$PLATFORM" = "ios" ] || [ "$PLATFORM" = "both" ]; then
echo "→ Building signed iOS release (.ipa)"
$RUN ios release
if [ "$UPLOAD" = true ]; then
echo "→ Uploading iOS release to TestFlight"
$RUN ios upload
fi
fi
echo "✓ Release build complete"
[ -f android/app/build/outputs/bundle/release/app-release.aab ] && echo " Android: android/app/build/outputs/bundle/release/app-release.aab"
[ -f build/ios/Donetick.ipa ] && echo " iOS: build/ios/Donetick.ipa"
echo ""
echo "Next steps:"
echo " git add . && git commit -m \"Release \$(node -p \"require('./package.json').version\")\""
echo " git tag v\$(node -p \"require('./package.json').version\") && git push origin develop --tags"

View File

@@ -1,17 +1,23 @@
import NavBar from '@/views/components/NavBar'
import { Button, Snackbar, Typography, useColorScheme } from '@mui/joy'
import Tracker from '@openreplay/tracker'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { useEffect, useState } from 'react'
import { Outlet } from 'react-router-dom'
import { Button, Typography, useColorScheme } from '@mui/joy'
import { useCallback, useEffect } from 'react'
import { Outlet, useNavigate } from 'react-router-dom'
import { useRegisterSW } from 'virtual:pwa-register/react'
import { registerCapacitorListeners } from './CapacitorListener'
import { UserContext } from './contexts/UserContext'
import { AuthenticationProvider } from './service/AuthenticationService'
import { ErrorProvider } from './service/ErrorProvider'
import { GetUserProfile } from './utils/Fetcher'
import { apiManager, isTokenValid } from './utils/TokenManager'
import PageTransition from './components/animations/PageTransition'
import { ImpersonateUserProvider } from './contexts/ImpersonateUserContext'
import { AuthProvider } from './hooks/useAuth.jsx'
import useStatusBar from './hooks/useStatusBar'
import { useResource } from './queries/ResourceQueries'
import './styles/safe-area.css'
import SSEProvider from './contexts/SSEContext'
import { useNotification } from './service/NotificationProvider'
import { useSyncOnReconnect } from './hooks/useSyncOnReconnect'
import NetworkBanner from './views/components/NetworkBanner'
const add = className => {
document.getElementById('root').classList.add(className)
}
@@ -19,24 +25,23 @@ const add = className => {
const remove = className => {
document.getElementById('root').classList.remove(className)
}
// TODO: Update the interval to at 60 minutes
const intervalMS = 5 * 60 * 1000 // 5 minutes
function App() {
startApiManager()
startOpenReplay()
const queryClient = new QueryClient()
const { mode, systemMode } = useColorScheme()
const [userProfile, setUserProfile] = useState(null)
const [showUpdateSnackbar, setShowUpdateSnackbar] = useState(true)
const AppContent = () => {
const { showNotification } = useNotification()
useSyncOnReconnect()
// Initialize status bar with theme-aware configuration
useStatusBar()
const {
offlineReady: [offlineReady, setOfflineReady],
offlineReady: [offlineReady, setOfflineReady], // eslint-disable-line no-unused-vars
needRefresh: [needRefresh, setNeedRefresh],
updateServiceWorker,
} = useRegisterSW({
onRegistered(r) {
// eslint-disable-next-line prefer-template
console.log('SW Registered: ' + r)
r &&
setInterval(() => {
@@ -47,12 +52,57 @@ function App() {
console.log('SW registration error', error)
},
})
const close = () => {
setOfflineReady(false)
setNeedRefresh(false)
}
const setThemeClass = () => {
useEffect(() => {
if (needRefresh) {
showNotification({
type: 'custom',
component: (
<div>
<Typography level='body-md'>
A new version is now available. Click on reload button to update.
</Typography>
<Button
color='secondary'
size='small'
onClick={() => {
updateServiceWorker(true)
setNeedRefresh(false)
}}
sx={{ ml: 2 }}
>
Refresh
</Button>
</div>
),
snackbarProps: {
autoHideDuration: null, // Persistent until user action
},
})
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [needRefresh])
return (
<div>
<ImpersonateUserProvider>
<NavBar />
<PageTransition>
<Outlet />
</PageTransition>
</ImpersonateUserProvider>
</div>
)
}
function App() {
const resource = useResource() // eslint-disable-line no-unused-vars
const { mode, systemMode } = useColorScheme()
const navigate = useNavigate()
// startOpenReplay()
const setThemeClass = useCallback(() => {
const value = JSON.parse(localStorage.getItem('themeMode')) || mode
if (value === 'system') {
@@ -67,68 +117,27 @@ function App() {
}
return remove('dark')
}
const getUserProfile = () => {
GetUserProfile()
.then(res => {
res.json().then(data => {
setUserProfile(data.res)
})
})
.catch(error => {})
}
}, [mode, systemMode])
useEffect(() => {
setThemeClass()
}, [mode, systemMode])
}, [setThemeClass])
useEffect(() => {
registerCapacitorListeners()
if (isTokenValid()) {
if (!userProfile) getUserProfile()
}
}, [])
registerCapacitorListeners(navigate)
}, [navigate])
return (
<div className='min-h-screen'>
<div>
<NetworkBanner />
<QueryClientProvider client={queryClient}>
<AuthenticationProvider />
<ErrorProvider>
<UserContext.Provider value={{ userProfile, setUserProfile }}>
<NavBar />
<Outlet />
</UserContext.Provider>
</ErrorProvider>
{needRefresh && (
<Snackbar open={showUpdateSnackbar}>
<Typography level='body-md'>
A new version is now available.Click on reload button to update.
</Typography>
<Button
color='secondary'
size='small'
onClick={() => {
updateServiceWorker(true)
setShowUpdateSnackbar(false)
}}
>
Refresh
</Button>
</Snackbar>
)}
</QueryClientProvider>
<AuthProvider>
<SSEProvider>
<AppContent />
</SSEProvider>
</AuthProvider>
</div>
)
}
const startOpenReplay = () => {
if (!import.meta.env.VITE_OPENREPLAY_PROJECT_KEY) return
const tracker = new Tracker({
projectKey: import.meta.env.VITE_OPENREPLAY_PROJECT_KEY,
})
tracker.start()
}
export default App
const startApiManager = () => {
apiManager.init()
}

View File

@@ -1,78 +1,290 @@
import { LocalNotifications } from '@capacitor/local-notifications';
import { App as mobileApp } from '@capacitor/app';
import { App as mobileApp } from '@capacitor/app'
import { Browser } from '@capacitor/browser'
import { Capacitor } from '@capacitor/core'
import { Device } from '@capacitor/device'
import { LocalNotifications } from '@capacitor/local-notifications'
import { Preferences } from '@capacitor/preferences'
import { PushNotifications } from '@capacitor/push-notifications'
import { PutNotificationTarget } from './utils/Fetcher';
import { Capacitor } from '@capacitor/core';
import { focusManager } from '@tanstack/react-query'
import { RegisterDeviceToken } from './utils/Fetcher'
// React Router navigate(), injected by <App /> once the router is mounted.
// Using client-side navigation (instead of window.location.href) avoids a full
// document reload, which on a cold NFC launch re-boots the app from an
// unauthenticated state (iOS "server/connection" error) and re-triggers the
// sticky getLaunchUrl() (Android "back reloads the same page").
let navigateFn = null
const setNavigate = fn => {
navigateFn = fn
}
// Navigate client-side when the router is available, otherwise fall back to a
// hard navigation (should only happen if a deep link arrives before mount).
const routerNavigate = (path, { seedHome = false } = {}) => {
if (navigateFn) {
// On a cold deep-link launch there is no real screen behind the target, so
// seed the chore list as the back target before pushing the chore view.
if (seedHome && window.location.pathname === '/') {
navigateFn('/chores', { replace: true })
}
navigateFn(path)
} else {
window.location.href = path
}
}
// Navigate to a chore from a deep link / notification tap. Shared by NFC,
// local and push notifications so they all get consistent cold-start handling.
const navigateToChore = (choreId, { autoComplete, isColdStart } = {}) => {
if (choreId == null || choreId === '') return
const path = `/chores/${choreId}${autoComplete ? '?auto_complete=' + autoComplete : ''}`
// If we're already on the target page, skip (avoids redundant navigation).
if (window.location.pathname + window.location.search === path) return
console.log('[deeplink] navigating to', path)
routerNavigate(path, { seedHome: isColdStart })
}
// NFC chore deep link: donetick://chores/123?auto_complete=true
const handleNFCChoreDeepLink = (url, isColdStart) => {
try {
const urlObj = new URL(url)
// donetick://chores/123 → host='chores', pathname='/123'
navigateToChore(urlObj.pathname.slice(1), {
autoComplete: urlObj.searchParams.get('auto_complete'),
isColdStart,
})
} catch (error) {
console.error('[NFC] Error handling chore deep link:', error)
}
}
const handleUrlOpen = (url, isColdStart = false) => {
console.log('[NFC] handleUrlOpen:', url)
if (url.startsWith('donetick://chores/')) {
handleNFCChoreDeepLink(url, isColdStart)
} else if (url.startsWith('donetick://auth/')) {
handleOAuthDeepLink(url)
}
}
// OAuth callback handler for deep links
const handleOAuthDeepLink = async url => {
console.log('OAuth deep link received:', url)
try {
// Parse the URL to extract code and state
const urlObj = new URL(url)
const code = urlObj.searchParams.get('code')
const state = urlObj.searchParams.get('state')
if (code && state) {
// If we're already on the OAuth handler page with the same code, skip
// re-navigating (a stale getLaunchUrl() replay would otherwise re-fire it).
const currentCode = new URLSearchParams(window.location.search).get(
'code',
)
if (window.location.pathname === '/auth/oauth2' && currentCode === code) {
return
}
// Store the OAuth params for the app to pick up
await Preferences.set({
key: 'oauth_callback',
value: JSON.stringify({ code, state, timestamp: Date.now() }),
})
// Close the browser if it's still open
try {
await Browser.close()
} catch (e) {
// Browser might already be closed
}
// Navigate to the OAuth handler page
routerNavigate(
`/auth/oauth2?code=${encodeURIComponent(code)}&state=${encodeURIComponent(state)}`,
)
}
} catch (error) {
console.error('Error handling OAuth deep link:', error)
}
}
const localNotificationListenerRegistration = () => {
LocalNotifications.addListener('localNotificationReceived', (notification) => {
console.log('Notification received', notification);
});
LocalNotifications.addListener('localNotificationActionPerformed', (event) => {
console.log('Notification action performed', event);
if (event.actionId === 'tap') {
console.log('Notification opened, navigate to chore', event.notification.extra.choreId);
window.location.href = `/chores/${event.notification.extra.choreId}`
}
});
}
const pushNotificationListenerRegistration = () => {
PushNotifications.register();
PushNotifications.addListener('registration', (token) => {
if (Capacitor.isNativePlatform()) {
const type = Capacitor.getPlatform() === 'android' ? 1 : 2; // 1 for android, 2 for ios
PutNotificationTarget(type, token.value).then((response) => {
console.log('Notification target updated', response);
}
).catch((error) => {
console.error('Error updating notification target', error);
}
);
LocalNotifications.addListener('localNotificationReceived', notification => {
console.log('Notification received', notification)
})
LocalNotifications.addListener('localNotificationActionPerformed', event => {
console.log('Notification action performed', event)
if (event.actionId === 'tap') {
console.log(
'Notification opened, navigate to chore',
event.notification.extra.choreId,
)
navigateToChore(event.notification.extra.choreId, { isColdStart: true })
}
})
}
// TODO save the token in preferences and only send it if it has changed:
console.log('Push registration success, token: ' + token.value);
}
const registerTokenIfNeeded = async (token, deviceInfo, deviceId, platform) => {
try {
const result = await RegisterDeviceToken(
token.value,
deviceId.identifier,
platform,
deviceInfo.appVersion,
deviceInfo.model,
)
if (!result) return
if (result.ok) {
await Preferences.set({
key: 'deviceRegistration',
value: JSON.stringify({
token: token.value,
deviceId: deviceId.identifier,
platform,
appVersion: deviceInfo.appVersion,
registeredAt: Date.now(),
}),
})
console.log('Device token registered successfully')
window.dispatchEvent(new CustomEvent('deviceTokenRegistered'))
} else {
console.error('Device registration failed:', result.status)
window.dispatchEvent(
new CustomEvent('deviceTokenRegistrationFailed', {
detail: {
status: result.status,
error: await result.text().catch(() => 'Unknown error'),
},
}),
)
}
);
PushNotifications.addListener('registrationError', (error) => {
console.error('Error on registration: ' + JSON.stringify(error));
} catch (error) {
console.error('Error registering device token:', error)
window.dispatchEvent(
new CustomEvent('deviceTokenRegistrationFailed', {
detail: { status: 0, error: error?.message ?? 'Unknown error' },
}),
)
}
}
const pushNotificationListenerRegistration = async () => {
// Check and request permissions for Android 13+
if (Capacitor.isNativePlatform()) {
let permStatus = await PushNotifications.checkPermissions()
if (permStatus.receive === 'prompt') {
permStatus = await PushNotifications.requestPermissions()
}
);
PushNotifications.addListener('pushNotificationActionPerformed', fcmEvent => {
if(fcmEvent.actionId === 'tap') {
if (fcmEvent.notification.data.type === 'chore_due') {
window.location.href = `/chores/${fcmEvent.notification.data.choreId}`
}
else {
window.location.href = `/my/chores`
}
if (permStatus.receive !== 'granted') {
console.warn('Push notification permission not granted')
return
}
}
);
}
await PushNotifications.register()
PushNotifications.addListener('registration', async token => {
if (Capacitor.isNativePlatform()) {
try {
const deviceInfo = await Device.getInfo()
const deviceId = await Device.getId()
const registerCapacitorListeners = () => {
if(!Capacitor.isNativePlatform()) {
console.log('Not a native platform, skipping registration of native listeners');
return
const platform =
Capacitor.getPlatform() === 'android' ? 'android' : 'ios'
await registerTokenIfNeeded(token, deviceInfo, deviceId, platform)
} catch (error) {
console.error('Error registering device token', error)
}
}
localNotificationListenerRegistration();
pushNotificationListenerRegistration();
mobileApp.addListener('backButton', ({ canGoBack }) => {
if (canGoBack) {
window.history.back();
} else {
mobileApp.exitApp();
}
});
})
PushNotifications.addListener('registrationError', error => {
console.error('Error on registration: ' + JSON.stringify(error))
})
PushNotifications.addListener('pushNotificationReceived', notification => {
console.log('Push notification received: ', notification)
})
PushNotifications.addListener('pushNotificationActionPerformed', fcmEvent => {
if (fcmEvent.actionId === 'tap') {
if (
fcmEvent.notification.data.type === 'chore_due' ||
fcmEvent.notification.data.type === 'nudge'
) {
navigateToChore(fcmEvent.notification.data.choreId, {
isColdStart: true,
})
} else {
routerNavigate('/chores')
}
}
})
}
let launchUrlHandled = false
let listenersRegistered = false
const registerCapacitorListeners = navigate => {
if (navigate) setNavigate(navigate)
if (!Capacitor.isNativePlatform()) {
console.log(
'Not a native platform, skipping registration of native listeners',
)
return
}
export { registerCapacitorListeners }
// registerCapacitorListeners runs from a React effect and may fire more than
// once; only wire up the native listeners a single time.
if (listenersRegistered) return
listenersRegistered = true
localNotificationListenerRegistration()
// Cold-start: app was launched by tapping an NFC tag (or other deep link).
// getLaunchUrl() is sticky and keeps returning the launch URL across reloads,
// so consume it exactly once to avoid re-triggering navigation on every boot.
mobileApp.getLaunchUrl().then(result => {
if (result?.url && !launchUrlHandled) {
launchUrlHandled = true
console.log('[NFC] getLaunchUrl:', result.url)
handleUrlOpen(result.url, true /* isColdStart */)
}
})
// Foreground / singleTask resume: app was already running when the tag was tapped
mobileApp.addListener('appUrlOpen', event => {
console.log('[NFC] appUrlOpen:', event.url)
handleUrlOpen(event.url, false /* isColdStart */)
})
mobileApp.addListener('appStateChange', ({ isActive }) => {
focusManager.setFocused(isActive)
})
mobileApp.addListener('backButton', ({ canGoBack }) => {
if (canGoBack) {
window.history.back()
} else if (window.location.pathname !== '/') {
// No history (e.g. app launched directly to a chore via NFC) — go home
window.location.href = '/'
} else {
mobileApp.exitApp()
}
})
}
export {
registerCapacitorListeners,
pushNotificationListenerRegistration as registerPushNotifications,
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 KiB

After

Width:  |  Height:  |  Size: 147 KiB

View File

@@ -0,0 +1,773 @@
import { Save } from '@mui/icons-material'
import AddIcon from '@mui/icons-material/Add'
import DeleteIcon from '@mui/icons-material/Delete'
import InfoIcon from '@mui/icons-material/Info'
import NotificationsIcon from '@mui/icons-material/Notifications'
import Alert from '@mui/joy/Alert'
import Badge from '@mui/joy/Badge'
import Box from '@mui/joy/Box'
import Button from '@mui/joy/Button'
import IconButton from '@mui/joy/IconButton'
import Input from '@mui/joy/Input'
import Option from '@mui/joy/Option'
import Select from '@mui/joy/Select'
import Typography from '@mui/joy/Typography'
import { useCallback, useEffect, useRef, useState } from 'react'
import { NOTIFICATION_TYPE, TASK_COLOR } from '../utils/Colors'
import { TIME_UNITS } from '../utils/DurationUtils'
const timeUnits = TIME_UNITS
const timingOptions = [
{ label: 'Before', value: 'before' },
{ label: 'Due', value: 'ondue' },
{ label: 'After', value: 'after' },
]
function getRelativeLabel(notification) {
const { value, unit } = notification
const numericValue = Number(value)
if (numericValue === 0) {
return 'On due date'
}
const unitName = unit === 'm' ? 'minutes' : unit === 'h' ? 'hours' : 'days'
const absValue = Math.abs(numericValue)
return `${absValue} ${unitName} ${numericValue < 0 ? 'before' : 'after'} due`
}
// Helper functions to convert between internal value and UI representation
function getUIRepresentation(notification) {
const numericValue = Number(notification.value)
if (numericValue === 0) {
return { timing: 'ondue', displayValue: 0, unit: notification.unit }
} else if (numericValue < 0) {
return {
timing: 'before',
displayValue: Math.abs(numericValue),
unit: notification.unit,
}
} else {
return {
timing: 'after',
displayValue: numericValue,
unit: notification.unit,
}
}
}
function getInternalValue(timing, displayValue) {
if (timing === 'ondue') return 0
if (timing === 'before') return -Math.abs(displayValue)
return Math.abs(displayValue) // 'after'
}
const NotificationTemplate = ({
maxNotifications = 5,
onChange,
value,
showTimeline = true,
}) => {
const [notifications, setNotifications] = useState(
value?.templates ||
JSON.parse(localStorage.getItem('defaultNotificationTemplate')) ||
[],
)
const notificationsRef = useRef(notifications)
const [draftValues, setDraftValues] = useState({})
const [error, setError] = useState(null)
const [showSaveDefault, setShowSaveDefault] = useState(false)
// Create a map of notification indices for timeline display
const [notificationIndexMap, setNotificationIndexMap] = useState({})
const updateNotificationIndices = useCallback(() => {
// Convert notifications to minutes for proper chronological sorting
const convertToMinutes = (value, unit) => {
const numericValue = Number(value)
if (numericValue === 0) return 0
let minutes = Math.abs(numericValue)
if (unit === 'h') minutes *= 60
if (unit === 'd') minutes *= 24 * 60
return numericValue < 0 ? -minutes : minutes
}
// Sort notifications for consistent ordering by actual time duration
const sorted = [...notifications].sort((a, b) => {
const aMinutes = convertToMinutes(a.value, a.unit)
const bMinutes = convertToMinutes(b.value, b.unit)
return aMinutes - bMinutes
})
const indexMap = {}
// Map original array indices to their chronological position numbers
notifications.forEach((originalNotification, originalIdx) => {
const chronologicalPosition = sorted.findIndex(
sortedNotification =>
Number(sortedNotification.value) ===
Number(originalNotification.value) &&
sortedNotification.unit === originalNotification.unit,
)
indexMap[originalIdx] = chronologicalPosition + 1
})
setNotificationIndexMap(indexMap)
}, [notifications])
// Sort notifications and update the index mapping
useEffect(() => {
updateNotificationIndices()
}, [updateNotificationIndices])
// Notify parent component of changes including the template name
useEffect(() => {
if (onChange) {
onChange({ notifications })
}
}, [notifications, onChange])
// Validates if a notification configuration already exists
const isDuplicate = (notification, currentIdx = -1, list = notifications) => {
return list.some((n, idx) => {
if (idx === currentIdx) return false
return (
Number(n.value) === Number(notification.value) &&
n.unit === notification.unit
)
})
}
const getSmartSuggestion = type => {
let suggestions = []
if (type === 'reminder' || type === 'before') {
suggestions = [
{ value: -1, unit: 'd' },
{ value: -3, unit: 'h' },
{ value: -30, unit: 'm' },
]
} else if (type === 'followup' || type === 'after') {
suggestions = [
{ value: 1, unit: 'd' },
{ value: 3, unit: 'd' },
{ value: 7, unit: 'd' },
]
}
return suggestions.find(
suggestion => !isDuplicate(suggestion, -1, notificationsRef.current),
)
}
const handleChange = (idx, field, value) => {
const currentNotification = notifications[idx]
const uiRep = getUIRepresentation(currentNotification)
let updatedUIRep = { ...uiRep }
let updatedNotification = { ...currentNotification }
// Update the UI representation based on the field being changed
if (field === 'timing') {
updatedUIRep.timing = value
// Reset display value when switching to "On Due"
if (value === 'ondue') {
updatedUIRep.displayValue = 0
} else if (Number(currentNotification.value) === 0) {
const suggestion = getSmartSuggestion(value)
if (suggestion) {
updatedUIRep.displayValue = Math.abs(suggestion.value)
updatedUIRep.unit = suggestion.unit
} else {
updatedUIRep.displayValue = 1
updatedUIRep.unit = 'h'
}
}
} else if (field === 'displayValue') {
updatedUIRep.displayValue = Math.max(0, Number(value))
} else if (field === 'unit') {
updatedUIRep.unit = value
updatedNotification.unit = value
}
// Convert back to internal representation
const newInternalValue = getInternalValue(
updatedUIRep.timing,
updatedUIRep.displayValue,
)
updatedNotification = {
...updatedNotification,
value: newInternalValue,
unit: updatedUIRep.unit,
}
const updated = notifications.map((n, i) =>
i === idx ? updatedNotification : n,
)
setNotifications(updated)
notificationsRef.current = updated
setError(null)
}
const handleBlur = idx => {
const currentList = notificationsRef.current
const currentNotification = currentList[idx]
if (!currentNotification) return
if (isDuplicate(currentNotification, idx, currentList)) {
setError(
'This notification setting already exists. Please use a different timing.',
)
return
}
}
const addSmartNotification = type => {
if (notifications.length >= maxNotifications) return
setShowSaveDefault(true)
let newNotification
if (type === 'due') {
if (notificationsRef.current.some(n => Number(n.value) === 0)) {
setError('Only one "Due Alert" notification is allowed.')
return
}
newNotification = { value: 0, unit: 'm' }
} else {
newNotification = getSmartSuggestion(type)
if (!newNotification) {
setError(`All common ${type} times are already configured.`)
return
}
}
// Add the new notification to the end (don't sort, keep form order)
const updatedNotifications = [...notifications, newNotification]
setNotifications(updatedNotifications)
notificationsRef.current = updatedNotifications
setError(null)
}
const removeNotification = idx => {
const updated = notifications.filter((_, i) => i !== idx)
setNotifications(updated)
notificationsRef.current = updated
setDraftValues(prev => {
const next = { ...prev }
delete next[idx]
return next
})
onChange && onChange(updated)
setShowSaveDefault(true)
}
const renderTimeline = () => {
// Convert notifications to minutes for proper chronological sorting
const convertToMinutes = (value, unit) => {
const numericValue = Number(value)
if (numericValue === 0) return 0
let minutes = Math.abs(numericValue)
if (unit === 'h') minutes *= 60
if (unit === 'd') minutes *= 24 * 60
return numericValue < 0 ? -minutes : minutes
}
// Sort notifications chronologically by actual time (in minutes)
const sorted = [...notifications].sort((a, b) => {
const aMinutes = convertToMinutes(a.value, a.unit)
const bMinutes = convertToMinutes(b.value, b.unit)
return aMinutes - bMinutes
})
// Get min and max notification times in minutes for dynamic scaling
const minutesValues = sorted.map(n => convertToMinutes(n.value, n.unit))
const minBefore = Math.min(0, ...minutesValues) // Default to 0 if no "before" notifications
const maxAfter = Math.max(0, ...minutesValues) // Default to 0 if no "after" notifications
const getPositionPercent = (value, unit) => {
const minutes = convertToMinutes(value, unit)
// Due date is always at center (50%)
if (minutes === 0) return 50
// For notifications before due date (negative values)
if (minutes < 0) {
if (minBefore === 0) return 30 // Default position if no before notifications
// Scale between 10% (furthest left) and 45% (closest to due)
return 45 - (Math.abs(minutes) / Math.abs(minBefore)) * 35
}
// For notifications after due date (positive values)
if (maxAfter === 0) return 70 // Default position if no after notifications
// Scale between 55% (closest to due) and 90% (furthest right)
return 55 + (minutes / maxAfter) * 35
}
return (
<Box sx={{ mt: 3, mb: 2 }}>
<Typography level={'body-md'} sx={{ mb: 1 }}>
Notification Timeline
</Typography>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
position: 'relative',
height: 90,
bgcolor: 'background.surface',
borderRadius: 'md',
border: '1px solid',
borderColor: 'neutral.outlinedBorder',
p: 2,
transition: 'height 0.3s ease',
// '&:hover': {
// height: 130,
// },
}}
>
{/* Timeline line */}
<Box
sx={{
position: 'relative',
width: '100%',
height: 3,
bgcolor: 'neutral.outlinedBorder',
mt: 2,
}}
>
{/* Due date marker */}
<Box
sx={{
position: 'absolute',
left: '50%',
height: 16,
width: 3,
bgcolor: 'warning.500',
top: -8,
transform: 'translateX(-50%)',
borderRadius: 'sm',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<Typography
level={'body-xs'}
sx={{
mt: 4,
fontWeight: 'md',
color: 'warning.700',
fontSize: '0.6rem',
}}
>
Due Date
</Typography>
</Box>
{/* Notification markers */}
{sorted.map((n, i) => {
// Calculate position based on actual time duration
const percent = getPositionPercent(n.value, n.unit)
return (
<Box
key={i}
sx={{
position: 'absolute',
left: `${percent}%`,
transform: 'translateX(-50%)',
color:
convertToMinutes(n.value, n.unit) < 0
? TASK_COLOR.SCHEDULED
: convertToMinutes(n.value, n.unit) === 0
? TASK_COLOR.TODAY
: TASK_COLOR.LATE,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
transition: 'all 0.3s ease',
cursor: 'pointer',
opacity: 0.85,
'&:hover': {
opacity: 1,
transform: 'translateX(-50%) scale(1.1)',
zIndex: 10,
},
}}
title={getRelativeLabel(n)}
>
<Badge
badgeContent={
notificationIndexMap[
notifications.findIndex(
original =>
Number(original.value) === Number(n.value) &&
original.unit === n.unit,
)
] || i + 1
}
size={'sm'}
variant={'solid'}
sx={{
'--Badge-paddingX': '4px',
'--Badge-minHeight': '16px',
'--Badge-fontSize': '0.65rem',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
'& .MuiBadge-badge': {
background:
convertToMinutes(n.value, n.unit) < 0
? NOTIFICATION_TYPE.PREDUE
: convertToMinutes(n.value, n.unit) === 0
? NOTIFICATION_TYPE.DUE_DATE
: NOTIFICATION_TYPE.POSTDUE,
color: 'white',
},
}}
>
<NotificationsIcon
fontSize={'small'}
sx={{
height: 18,
width: 18,
}}
/>
</Badge>
</Box>
)
})}
</Box>
</Box>
</Box>
)
}
return (
<Box>
{error && (
<Alert
variant='soft'
color='danger'
sx={{ mb: 2 }}
startDecorator={<InfoIcon />}
>
{error}
</Alert>
)}
{notifications
.map((n, idx) => ({ notification: n, originalIndex: idx }))
.sort((a, b) => {
const aBadgeNumber = notificationIndexMap[a.originalIndex] || 0
const bBadgeNumber = notificationIndexMap[b.originalIndex] || 0
return aBadgeNumber - bBadgeNumber
})
.map(({ notification: n, originalIndex: idx }) => {
// Get ordered badge number from timeline sorting
const badgeNumber = notificationIndexMap[idx]
const uiRep = getUIRepresentation(n)
// Check if an "On Due" notification exists anywhere else in the list
const hasOnDueElsewhere = notificationsRef.current.some(
(notif, i) => i !== idx && Number(notif.value) === 0,
)
const getNotificationColors = value => {
if (Number(value) < 0) {
return {
bgColor: NOTIFICATION_TYPE.PREDUE,
lightBg: `${NOTIFICATION_TYPE.PREDUE}20`,
borderColor: `${NOTIFICATION_TYPE.PREDUE}40`,
textColor: NOTIFICATION_TYPE.PREDUE,
}
} else if (Number(value) === 0) {
return {
bgColor: NOTIFICATION_TYPE.DUE_DATE,
lightBg: `${NOTIFICATION_TYPE.DUE_DATE}20`,
borderColor: `${NOTIFICATION_TYPE.DUE_DATE}40`,
textColor: NOTIFICATION_TYPE.DUE_DATE,
}
} else {
return {
bgColor: NOTIFICATION_TYPE.POSTDUE,
lightBg: `${NOTIFICATION_TYPE.POSTDUE}20`,
borderColor: `${NOTIFICATION_TYPE.POSTDUE}40`,
textColor: NOTIFICATION_TYPE.POSTDUE,
}
}
}
const colors = getNotificationColors(n.value)
return (
<Box key={idx} sx={{ position: 'relative' }}>
<Badge
badgeContent={badgeNumber}
size={'sm'}
sx={{
'--Badge-minHeight': '16px',
'--Badge-fontSize': '0.7rem',
'--Badge-paddingX': '5px',
top: 10,
left: 10,
'& .MuiBadge-badge': {
background: colors.bgColor,
color: 'white',
},
}}
/>
<Box
sx={{
mb: 1.5,
p: 2,
borderRadius: 8,
border: '1px solid',
borderColor: 'neutral.outlinedBorder',
background: 'background.surface',
transition: 'all 0.2s ease',
display: 'flex',
alignItems: 'center',
gap: 1.5,
}}
>
<Box
sx={{
minWidth: 0,
flex: '1',
display: { xs: 'none', md: 'flex' }, // Show only on md and up
}}
>
<Typography
level='body-sm'
sx={{
fontWeight: 600,
color: 'text.primary',
fontSize: 14,
}}
>
{getRelativeLabel(n)}
</Typography>
</Box>
<Box
sx={{
display: 'flex',
alignItems: 'center',
gap: 1,
flexShrink: 0,
}}
>
<Select
value={uiRep.timing}
onChange={(_, value) => handleChange(idx, 'timing', value)}
onBlur={() => handleBlur(idx)}
sx={{ minWidth: 80 }}
size={'sm'}
>
{timingOptions.map(opt => (
<Option
key={opt.value}
value={opt.value}
disabled={opt.value === 'ondue' && hasOnDueElsewhere}
>
{opt.label}
</Option>
))}
</Select>
<Input
type={'number'}
min={0}
value={
draftValues[idx] !== undefined
? draftValues[idx]
: uiRep.displayValue
}
disabled={uiRep.timing === 'ondue'}
onChange={e => {
const val = e.target.value
if (val.includes('-')) return
setDraftValues(prev => ({ ...prev, [idx]: val }))
}}
onKeyDown={e => {
if (['-', 'e', '+', '.'].includes(e.key)) {
e.preventDefault()
}
}}
onBlur={e => {
let val = e.target.value
const numericVal = Number(val)
val =
numericVal <= 0
? hasOnDueElsewhere
? 1
: 0
: numericVal
handleChange(idx, 'displayValue', val)
setDraftValues(prev => {
const next = { ...prev }
delete next[idx]
return next
})
handleBlur(idx)
}}
sx={{
width: 60,
opacity: uiRep.timing === 'ondue' ? 0.6 : 1,
}}
size={'sm'}
placeholder='0'
/>
<Select
value={n.unit}
disabled={uiRep.timing === 'ondue'}
onChange={(_, value) => handleChange(idx, 'unit', value)}
onBlur={() => handleBlur(idx)}
sx={{
minWidth: 70,
opacity: uiRep.timing === 'ondue' ? 0.6 : 1,
}}
size={'sm'}
>
{timeUnits.map(opt => (
<Option key={opt.value} value={opt.value}>
{opt.label}
</Option>
))}
</Select>
<IconButton
onClick={() => removeNotification(idx)}
disabled={notifications.length === 1}
color={'danger'}
size={'sm'}
variant={'soft'}
sx={{
transition: 'all 0.2s ease',
'&:hover': {
transform: 'scale(1.1)',
},
}}
>
<DeleteIcon fontSize={'small'} />
</IconButton>
</Box>
</Box>
</Box>
)
})}
<Box
sx={{
display: 'flex',
gap: 1.5,
mt: 1,
mb: 2,
flexWrap: 'wrap',
}}
>
<Button
onClick={() => addSmartNotification('reminder')}
disabled={notifications.length >= maxNotifications}
startDecorator={<AddIcon />}
size={'sm'}
variant={'outlined'}
sx={{
borderRadius: 6,
fontWeight: 500,
borderColor: `${TASK_COLOR.SCHEDULED}60`,
color: TASK_COLOR.SCHEDULED,
'&:hover': {
borderColor: TASK_COLOR.SCHEDULED,
background: `${TASK_COLOR.SCHEDULED}10`,
},
}}
>
Reminder
</Button>
<Button
onClick={() => addSmartNotification('due')}
disabled={
notifications.length >= maxNotifications ||
notifications.some(n => Number(n.value) === 0)
}
startDecorator={<AddIcon />}
size={'sm'}
variant={'outlined'}
sx={{
borderRadius: 6,
fontWeight: 500,
borderColor: `${NOTIFICATION_TYPE.DUE_DATE}60`,
color: NOTIFICATION_TYPE.DUE_DATE,
'&:hover': {
borderColor: NOTIFICATION_TYPE.DUE_DATE,
background: `${NOTIFICATION_TYPE.DUE_DATE}10`,
},
}}
>
Due Alert
</Button>
<Button
onClick={() => addSmartNotification('followup')}
disabled={notifications.length >= maxNotifications}
startDecorator={<AddIcon />}
size={'sm'}
variant={'outlined'}
sx={{
borderRadius: 6,
fontWeight: 500,
borderColor: `${NOTIFICATION_TYPE.POSTDUE}60`,
color: NOTIFICATION_TYPE.POSTDUE,
'&:hover': {
borderColor: NOTIFICATION_TYPE.POSTDUE,
background: `${NOTIFICATION_TYPE.POSTDUE}10`,
},
}}
>
Follow-up
</Button>
</Box>
{showSaveDefault && (
<Box
sx={{
mt: 1,
display: 'flex',
justifyContent: 'start',
alignItems: 'center',
gap: 1,
}}
>
<Button
variant='outlined'
size='sm'
color='neutral'
startDecorator={<Save />}
sx={{
borderRadius: 6,
fontWeight: 500,
'&:hover': {
background: 'neutral.softHoverBg',
},
}}
onClick={() => {
localStorage.setItem(
'defaultNotificationTemplate',
JSON.stringify(notifications),
)
setShowSaveDefault(false)
}}
>
Remember for Future Tasks
</Button>
</Box>
)}
{showTimeline && renderTimeline()}
</Box>
)
}
export default NotificationTemplate

View File

@@ -0,0 +1,192 @@
import { Sync, SyncDisabled } from '@mui/icons-material'
import { Box, Card, Chip, FormHelperText, Switch, Typography } from '@mui/joy'
import { useState } from 'react'
import { useSSEContext } from '../hooks/useSSEContext'
import { useUserProfile } from '../queries/UserQueries'
import { isPlusAccount } from '../utils/Helpers'
import SSEConnectionStatus from './SSEConnectionStatus'
const REALTIME_TYPES = {
DISABLED: 'disabled',
SSE: 'sse',
}
const RealTimeSettings = () => {
const { data: userProfile } = useUserProfile()
// SSE context
const sseContext = useSSEContext()
// Get current realtime type from localStorage
const getCurrentRealtimeType = () => {
const sseEnabled = localStorage.getItem('sse_enabled') === 'true'
return sseEnabled ? REALTIME_TYPES.SSE : REALTIME_TYPES.DISABLED
}
const [realtimeType, setRealtimeType] = useState(getCurrentRealtimeType())
const handleRealtimeTypeChange = (event, newValue) => {
if (!isPlusAccount(userProfile)) {
return // Don't allow changes for non-Plus users
}
setRealtimeType(newValue)
// Update localStorage and toggle connections
switch (newValue) {
case REALTIME_TYPES.DISABLED:
localStorage.setItem('sse_enabled', 'false')
sseContext.disconnect()
break
case REALTIME_TYPES.SSE:
localStorage.setItem('sse_enabled', 'true')
sseContext.connect()
break
}
}
const getCurrentContext = () => {
switch (realtimeType) {
case REALTIME_TYPES.SSE:
return sseContext
default:
return {
isConnected: false,
isConnecting: false,
error: null,
getConnectionStatus: () => 'disabled',
}
}
}
const context = getCurrentContext()
const getStatusDescription = () => {
if (!isPlusAccount(userProfile)) {
return 'Real-time updates are not available in the Basic plan. Upgrade to Plus to receive instant notifications when tasks are updated.'
}
if (realtimeType === REALTIME_TYPES.DISABLED) {
return 'Real-time updates are disabled. Enable them to see live changes when you or other circle members complete, skip, or modify tasks.'
}
if (context.isConnected) {
return "Real-time updates are working. You'll see live changes when you or other circle members complete, skip, or modify tasks."
}
if (context.isConnecting) {
return 'Connecting to real-time updates...'
}
if (context.error) {
return `Real-time updates are enabled but not working: ${context.error}`
}
return 'Real-time updates are enabled but not currently connected.'
}
const getConnectionStatusComponent = () => {
switch (realtimeType) {
case REALTIME_TYPES.SSE:
return <SSEConnectionStatus variant='chip' />
default:
return null
}
}
return (
<Card sx={{ mt: 2, p: 3 }}>
<Box sx={{ display: 'flex', alignItems: 'flex-start', gap: 2, mb: 2 }}>
<Switch
checked={realtimeType !== REALTIME_TYPES.DISABLED}
onChange={e => {
handleRealtimeTypeChange(
null,
e.target.checked ? REALTIME_TYPES.SSE : REALTIME_TYPES.DISABLED,
)
}}
color={
realtimeType !== REALTIME_TYPES.DISABLED ? 'success' : 'neutral'
}
disabled={!isPlusAccount(userProfile)}
inputProps={{ 'aria-label': 'Enable Real-time Updates' }}
/>
<Box sx={{ flex: 1 }}>
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
mb: 0.5,
}}
>
<Typography level='title-md'>
Real-time Updates
{!isPlusAccount(userProfile) && (
<Chip variant='soft' color='warning' sx={{ ml: 1 }}>
Plus Feature
</Chip>
)}
</Typography>
{realtimeType !== REALTIME_TYPES.DISABLED &&
isPlusAccount(userProfile) ? (
<Sync color={context.isConnected ? 'success' : 'disabled'} />
) : (
<SyncDisabled color='disabled' />
)}
</Box>
<Typography level='body-sm' color='neutral'>
Get instant notifications when tasks are updated
</Typography>
</Box>
</Box>
{/* <FormControl orientation='horizontal' sx={{ mb: 2 }}>
<Box sx={{ flex: 1 }}>
<FormLabel>Real-time Connection Type</FormLabel>
<FormHelperText sx={{ mt: 0 }}>
Choose how to receive real-time updates
</FormHelperText>
</Box>
<Select
value={realtimeType}
onChange={handleRealtimeTypeChange}
disabled={!isPlusAccount(userProfile)}
sx={{ minWidth: 140 }}
>
<Option value={REALTIME_TYPES.DISABLED}>Disabled</Option>
<Option value={REALTIME_TYPES.WEBSOCKET}>WebSocket</Option>
<Option value={REALTIME_TYPES.SSE}>SSE</Option>
</Select>
</FormControl> */}
<FormHelperText sx={{ mb: 2 }}>{getStatusDescription()}</FormHelperText>
{realtimeType !== REALTIME_TYPES.DISABLED &&
isPlusAccount(userProfile) && (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mt: 1 }}>
<Typography level='body-xs' color='neutral'>
Status:
</Typography>
{getConnectionStatusComponent()}
{context.error && (
<Typography level='body-xs' color='danger'>
{context.error}
</Typography>
)}
</Box>
)}
{!isPlusAccount(userProfile) && (
<Typography level='body-sm' color='warning' sx={{ mt: 1 }}>
Real-time updates are not available in the Basic plan. Upgrade to Plus
to receive instant notifications when you or other circle members
complete, skip, or modify tasks.
</Typography>
)}
</Card>
)
}
export default RealTimeSettings

View File

@@ -0,0 +1,106 @@
import { Circle, SignalWifi4Bar, SignalWifiOff } from '@mui/icons-material'
import { Box, Chip, Tooltip, Typography } from '@mui/joy'
import { useSSEContext } from '../hooks/useSSEContext'
const SSEConnectionStatus = ({
variant = 'minimal',
showError = false,
sx = {},
}) => {
const { isConnected, isConnecting, error, getConnectionStatus } =
useSSEContext()
const getStatusColor = () => {
if (isConnected) return 'success'
if (isConnecting) return 'warning'
return 'danger'
}
const getStatusIcon = () => {
if (isConnected) return <SignalWifi4Bar />
if (isConnecting) return <Circle />
return <SignalWifiOff />
}
const getStatusText = () => {
if (isConnected) return 'Connected'
if (isConnecting) return 'Connecting...'
return 'Disconnected'
}
const getTooltipText = () => {
const status = getConnectionStatus()
if (error) return `Real-time updates (SSE): ${status} - ${error}`
if (!isConnected && !isConnecting) {
return `Real-time updates (SSE): ${status} - Join a circle to enable real-time updates`
}
return `Real-time updates (SSE): ${status}`
}
if (variant === 'minimal') {
return (
<Tooltip title={getTooltipText()} size='sm'>
<Box
sx={{
display: 'flex',
alignItems: 'center',
gap: 0.5,
...sx,
}}
>
<Circle
sx={{
fontSize: 8,
color:
getStatusColor() === 'success'
? 'success.main'
: getStatusColor() === 'warning'
? 'warning.main'
: 'danger.main',
}}
/>
{showError && error && (
<Typography level='body-xs' color='danger'>
{error}
</Typography>
)}
</Box>
</Tooltip>
)
}
if (variant === 'chip') {
return (
<Tooltip title={getTooltipText()} size='sm'>
<Chip
color={getStatusColor()}
size='sm'
variant='soft'
startDecorator={getStatusIcon()}
sx={sx}
>
{getStatusText()}
</Chip>
</Tooltip>
)
}
// Full variant
return (
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1, ...sx }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
{getStatusIcon()}
<Typography level='body-sm' color={getStatusColor()}>
{getStatusText()}
</Typography>
</Box>
{showError && error && (
<Typography level='body-xs' color='danger'>
{error}
</Typography>
)}
</Box>
)
}
export default SSEConnectionStatus

View File

@@ -0,0 +1,149 @@
import { Sync, SyncDisabled } from '@mui/icons-material'
import {
Box,
Card,
Chip,
FormControl,
FormHelperText,
FormLabel,
Switch,
Typography,
} from '@mui/joy'
import { useSSEContext } from '../hooks/useSSEContext'
import { useUserProfile } from '../queries/UserQueries'
import { isPlusAccount } from '../utils/Helpers'
import SSEConnectionStatus from './SSEConnectionStatus'
const SSESettings = () => {
const { data: userProfile } = useUserProfile()
const {
isConnected,
isConnecting,
error,
getConnectionStatus,
toggleSSEEnabled,
isSSEEnabled,
} = useSSEContext()
const handleToggle = () => {
console.log('=== TOGGLE CLICKED ===')
if (!isPlusAccount(userProfile)) {
console.log('Not a Plus account, returning early')
return // Don't allow toggle for non-Plus users
}
const currentlyEnabled = isSSEEnabled()
console.log('SSE Settings - Toggle clicked:', {
currentlyEnabled,
newState: !currentlyEnabled,
userProfile,
isPlusAccount: isPlusAccount(userProfile),
})
toggleSSEEnabled(!currentlyEnabled)
}
const getStatusDescription = () => {
if (!isPlusAccount(userProfile)) {
return 'Real-time updates (SSE) are not available in the Basic plan. Upgrade to Plus to receive instant notifications when chores are updated.'
}
if (!isSSEEnabled()) {
return 'Real-time updates (SSE) are disabled. Enable to see live changes when you or other circle members complete, skip, or modify chores.'
}
if (isConnected) {
return "Real-time updates (SSE) are working. You'll see live changes when you or other circle members complete, skip, or modify chores."
}
if (isConnecting) {
return 'Connecting to real-time updates (SSE)...'
}
if (error) {
return `Real-time updates (SSE) are enabled but not working: ${error}`
}
return 'Real-time updates (SSE) are enabled but not currently connected.'
}
return (
<Card sx={{ mt: 2, p: 3 }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2, mb: 2 }}>
{isSSEEnabled() && isPlusAccount(userProfile) ? (
<Sync color={isConnected ? 'success' : 'disabled'} />
) : (
<SyncDisabled color='disabled' />
)}
<Box sx={{ flex: 1 }}>
<Typography level='title-md'>
Real-time Updates (SSE)
{!isPlusAccount(userProfile) && (
<Chip variant='soft' color='warning' sx={{ ml: 1 }}>
Plus Feature
</Chip>
)}
</Typography>
<Typography level='body-sm' color='neutral'>
Get instant notifications via Server-Sent Events
</Typography>
</Box>
{isSSEEnabled() && isPlusAccount(userProfile) && (
<SSEConnectionStatus variant='chip' />
)}
</Box>
<FormControl orientation='horizontal' sx={{ mb: 2 }}>
<Box sx={{ flex: 1 }}>
<FormLabel>Enable Real-time Updates (SSE)</FormLabel>
<FormHelperText sx={{ mt: 0 }}>
{getStatusDescription()}
</FormHelperText>
</Box>
<Switch
checked={isSSEEnabled() && isPlusAccount(userProfile)}
onChange={handleToggle}
disabled={!isPlusAccount(userProfile)}
color={
isSSEEnabled() && isPlusAccount(userProfile) ? 'success' : 'neutral'
}
variant='solid'
endDecorator={
isSSEEnabled() && isPlusAccount(userProfile) ? 'On' : 'Off'
}
slotProps={{ endDecorator: { sx: { minWidth: 24 } } }}
/>
</FormControl>
{isSSEEnabled() && isPlusAccount(userProfile) && (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mt: 1 }}>
<Typography level='body-xs' color='neutral'>
Status:
</Typography>
<Chip
size='sm'
variant='soft'
color={
isConnected ? 'success' : isConnecting ? 'warning' : 'danger'
}
>
{getConnectionStatus()}
</Chip>
{error && (
<Typography level='body-xs' color='danger'>
{error}
</Typography>
)}
</Box>
)}
{!isPlusAccount(userProfile) && (
<Typography level='body-sm' color='warning' sx={{ mt: 1 }}>
Real-time updates (SSE) are not available in the Basic plan. Upgrade
to Plus to receive instant notifications when you or other circle
members complete, skip, or modify chores.
</Typography>
)}
</Card>
)
}
export default SSESettings

View File

@@ -0,0 +1,259 @@
import { Check, Star } from '@mui/icons-material'
import {
Box,
Button,
Card,
Chip,
Divider,
Modal,
ModalDialog,
Radio,
Typography,
} from '@mui/joy'
import { useState } from 'react'
import { useNotification } from '../service/NotificationProvider'
import { GetSubscriptionSession } from '../utils/Fetcher'
const SubscriptionModal = ({ open, onClose }) => {
const [selectedPlan, setSelectedPlan] = useState('yearly')
const [isLoading, setIsLoading] = useState(false)
const { showError } = useNotification()
const plans = {
yearly: {
price: '$39.00',
period: 'year',
total: '$39.00/year',
// savings: 'Save $20.88',
// popular: true,
},
// monthly: {
// price: '$4.99',
// period: 'month',
// total: '$4.99/month',
// savings: null,
// },
}
const features = [
'Task notifications and reminders',
'Rich text descriptions with images uploads',
'Thing-based task triggers',
'API tokens for integrations',
'Image uploads in descriptions',
'Advanced task automation',
// 'Unlimited task history',
// 'Unlimited things history',
]
const handleSubscribe = async () => {
setIsLoading(true)
try {
// Call the backend with the selected plan
const response = await GetSubscriptionSession()
if (!response.ok) {
throw new Error('Failed to create subscription session')
}
const data = await response.json()
// Redirect to Stripe
if (data.sessionURL) {
window.location.href = data.sessionURL
} else {
throw new Error('No session URL received')
}
} catch (error) {
console.error('Subscription error:', error)
showError({
title: 'Subscription Error',
message: 'Failed to start subscription process. Please try again.',
})
} finally {
setIsLoading(false)
}
}
return (
<Modal open={open} onClose={onClose}>
<ModalDialog
layout='center'
sx={{
width: 600,
maxWidth: '95vw',
maxHeight: '95vh',
overflow: 'auto',
p: 0,
}}
>
<Box sx={{ p: 4 }}>
{/* Header */}
<Box sx={{ textAlign: 'center', mb: 4 }}>
<Typography level='h3' sx={{ mb: 1 }}>
Upgrade to Plus
</Typography>
</Box>
{/* Features List */}
<Box sx={{ mb: 2 }}>
<Typography level='title-lg' sx={{ mb: 2 }}>
What&apos;s included:
</Typography>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>
{features.map((feature, index) => (
<Box
key={index}
sx={{ display: 'flex', alignItems: 'center', gap: 2 }}
>
<Check color='success' sx={{ fontSize: 20 }} />
<Typography level='body-md'>{feature}</Typography>
</Box>
))}
</Box>
</Box>
<Divider sx={{ my: 3 }} />
{/* Plan Selection */}
<Box
sx={{ display: 'flex', flexDirection: 'column', gap: 1.2, mb: 4 }}
>
{Object.entries(plans).map(([key, plan]) => (
<Card
key={key}
color={selectedPlan === key ? 'primary' : 'neutral'}
onClick={() => setSelectedPlan(key)}
sx={{
width: '100%',
minHeight: 48,
maxHeight: 64,
cursor: 'pointer',
transition: 'all 0.2s',
mb: 0.2,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
px: 2.5,
py: 1.2,
position: 'relative',
overflow: 'visible',
}}
>
<Box
sx={{
display: 'flex',
alignItems: 'center',
gap: 2,
justifyContent: 'flex-start',
width: '100%',
}}
>
<Radio
checked={selectedPlan === key}
onChange={() => setSelectedPlan(key)}
value={key}
name='subscription-plan'
color='primary'
sx={{ mr: 1 }}
/>
<Typography level='body-md' sx={{ fontWeight: 600 }}>
{key.charAt(0).toUpperCase() + key.slice(1)}
</Typography>
<Typography level='body-sm' sx={{ fontWeight: 500, ml: 1 }}>
{plan.price}
<span style={{ color: '#888', fontWeight: 400 }}>
{' '}
/ {plan.period}
</span>
</Typography>
</Box>
<Box
sx={{
display: 'flex',
alignItems: 'center',
gap: 0.5,
position: 'absolute',
right: 16,
top: -18,
}}
>
{plan.popular && (
<Chip
variant='solid'
color='warning'
size='sm'
startDecorator={<Star />}
sx={{
fontWeight: 600,
fontSize: 12,
px: 1,
py: 0.1,
boxShadow: 2,
mt: 0.8,
}}
>
Most Popular
</Chip>
)}
{plan.savings && (
<Chip
variant='soft'
color='success'
size='sm'
sx={{
fontWeight: 600,
fontSize: 12,
px: 1,
py: 0.1,
boxShadow: 2,
mt: 0.8,
}}
>
{plan.savings}
</Chip>
)}
</Box>
</Card>
))}
</Box>
{/* Action Buttons */}
<Box
sx={{ display: 'flex', flexDirection: 'column', gap: 1.2, mt: 2 }}
>
<Button
variant='solid'
color='primary'
onClick={handleSubscribe}
loading={isLoading}
fullWidth
size='lg'
sx={{ mb: 1 }}
>
Subscribe
</Button>
<Button
variant='plain'
onClick={onClose}
disabled={isLoading}
fullWidth
>
Cancel
</Button>
</Box>
{/* Footer */}
<Typography
level='body-xs'
color='neutral'
sx={{ textAlign: 'center', mt: 3 }}
>
Cancel anytime. No hidden fees. Secure payment powered by Stripe.
</Typography>
</Box>
</ModalDialog>
</Modal>
)
}
export default SubscriptionModal

View File

@@ -0,0 +1,539 @@
import {
AdminPanelSettings,
DarkModeOutlined,
GroupAdd,
LightModeOutlined,
Logout,
Person,
Settings,
SwapHoriz,
Tune,
WorkspacePremium,
} from '@mui/icons-material'
import {
Avatar,
Box,
Divider,
Dropdown,
ListItemContent,
ListItemDecorator,
Menu,
MenuButton,
MenuItem,
Sheet,
Typography,
useColorScheme,
} from '@mui/joy'
import { useMediaQuery } from '@mui/material'
import moment from 'moment'
import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { useImpersonateUser } from '../contexts/ImpersonateUserContext'
import useStickyState from '../hooks/useStickyState'
import { useCircleMembers, useUserProfile } from '../queries/UserQueries'
import { apiClient } from '../utils/ApiClient'
import { isPlusAccount, resolvePhotoURL } from '../utils/Helpers'
import UserModal from '../views/Modals/Inputs/UserModal'
import SubscriptionModal from './SubscriptionModal'
const UserProfileAvatar = () => {
const navigate = useNavigate()
const { mode, setMode } = useColorScheme()
const { data: userProfile } = useUserProfile()
const {
isImpersonating,
startImpersonation,
stopImpersonation,
canImpersonate,
getEffectiveUser,
} = useImpersonateUser()
const { data: circleMembersData } = useCircleMembers()
const [isModalOpen, setIsModalOpen] = useState(false)
const [isSubscriptionModalOpen, setIsSubscriptionModalOpen] = useState(false)
const [themeMode, setThemeMode] = useStickyState(mode, 'themeMode')
const isLargeScreen = useMediaQuery(theme => theme.breakpoints.up('lg'))
if (!userProfile) return null
const currentUser = getEffectiveUser(userProfile)
const isAdmin = canImpersonate(userProfile, circleMembersData?.res)
const isPlusUser = isPlusAccount(userProfile)
const getSubscriptionStatus = () => {
if (!userProfile) return 'Free'
if (userProfile.subscription === 'active') {
return 'Plus'
}
if (
userProfile.subscription === 'cancelled' &&
moment().isBefore(userProfile.expiration)
) {
return 'Plus (expires soon)'
}
return 'Free'
}
const handleLogout = () => {
apiClient.handleLogout()
}
const handleSupportEmail = () => {
window.location.href = 'mailto:support@donetick.com'
}
const isDarkMode = themeMode === 'dark'
const handleThemeToggle = () => {
const newThemeMode = isDarkMode ? 'light' : 'dark'
setThemeMode(newThemeMode)
setMode(newThemeMode)
}
return (
<>
<Dropdown>
<MenuButton
variant='plain'
sx={{
p: 0,
border: 'none',
backgroundColor: 'transparent',
borderRadius: '50%',
'&:hover': {
backgroundColor: 'var(--joy-palette-neutral-softHoverBg)',
// transform: 'scale(1.05)',
// transition: 'all 0.2s ease',
},
'&:active': {
// transform: 'scale(0.95)',
},
}}
>
<Box sx={{ position: 'relative' }}>
{isImpersonating ? (
<Box sx={{ position: 'relative' }}>
<Avatar
src={resolvePhotoURL(currentUser?.image)}
alt={currentUser?.displayName || currentUser?.name}
size='md'
sx={{
width: 36,
height: 36,
border: '2px solid var(--joy-palette-background-surface)',
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
}}
/>
<Avatar
src={resolvePhotoURL(userProfile?.image || userProfile?.avatar)}
alt={userProfile?.displayName || userProfile?.name}
size='sm'
sx={{
position: 'absolute',
bottom: -2,
left: -2,
width: 18,
height: 18,
border: '2px solid var(--joy-palette-background-surface)',
backgroundColor: 'var(--joy-palette-background-surface)',
boxShadow: '0 1px 4px rgba(0,0,0,0.2)',
}}
/>
<Box
sx={{
position: 'absolute',
top: -2,
right: -2,
width: 14,
height: 14,
borderRadius: '50%',
backgroundColor: 'var(--joy-palette-primary-500)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
border: '1px solid var(--joy-palette-background-surface)',
boxShadow: '0 1px 2px rgba(0,0,0,0.2)',
}}
>
<SwapHoriz sx={{ fontSize: 8, color: 'white' }} />
</Box>
</Box>
) : (
<Avatar
src={resolvePhotoURL(currentUser?.image || currentUser?.avatar)}
alt={currentUser?.displayName || currentUser?.name}
size='md'
sx={{
width: 36,
height: 36,
border: '2px solid var(--joy-palette-background-surface)',
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
}}
/>
)}
</Box>
</MenuButton>
<Menu
placement='bottom-end'
sx={{
minWidth: 280,
p: 1,
'--List-gap': '4px',
boxShadow: 'var(--joy-shadow-lg)',
border: '1px solid var(--joy-palette-divider)',
borderRadius: 'var(--joy-radius-md)',
}}
>
<Sheet sx={{ p: 2, borderRadius: 'var(--joy-radius-sm)', mb: 1 }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
<Avatar
src={resolvePhotoURL(currentUser?.image || currentUser?.avatar)}
alt={currentUser?.displayName || currentUser?.name}
size='lg'
sx={{
width: 48,
height: 48,
border: '2px solid var(--joy-palette-background-surface)',
}}
/>
<Box sx={{ flex: 1, minWidth: 0 }}>
<Typography
level='title-md'
sx={{
fontWeight: 600,
color: 'var(--joy-palette-text-primary)',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
mb: 0.25,
}}
>
{currentUser?.displayName || currentUser?.name}
</Typography>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
<Typography
level='body-sm'
sx={{
color: 'var(--joy-palette-text-tertiary)',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
flex: 1,
}}
>
{currentUser?.email}
</Typography>
{isPlusUser && (
<Typography
level='body-xs'
sx={{
color: 'var(--joy-palette-warning-600)',
fontWeight: 500,
fontSize: '11px',
}}
>
{getSubscriptionStatus()}
</Typography>
)}
</Box>
{isImpersonating && (
<Box
sx={{
display: 'flex',
alignItems: 'center',
gap: 0.5,
mt: 0.5,
px: 1,
py: 0.25,
backgroundColor: 'var(--joy-palette-primary-softBg)',
borderRadius: 'var(--joy-radius-sm)',
width: 'fit-content',
}}
>
<SwapHoriz
sx={{
fontSize: 12,
color: 'var(--joy-palette-primary-600)',
}}
/>
<Typography
level='body-xs'
sx={{
color: 'var(--joy-palette-primary-600)',
fontWeight: 500,
}}
>
Impersonating
</Typography>
</Box>
)}
</Box>
</Box>
</Sheet>
{isAdmin && (
<>
<MenuItem
onClick={() => setIsModalOpen(true)}
sx={{
borderRadius: 'var(--joy-radius-sm)',
'&:hover': {
backgroundColor: 'var(--joy-palette-neutral-softHoverBg)',
},
}}
>
<ListItemDecorator
sx={{ color: 'var(--joy-palette-primary-500)' }}
>
<AdminPanelSettings />
</ListItemDecorator>
<ListItemContent>
<Typography level='body-sm' sx={{ fontWeight: 500 }}>
{isImpersonating ? 'Switch User' : 'Impersonate User'}
</Typography>
<Typography
level='body-xs'
sx={{ color: 'var(--joy-palette-text-tertiary)' }}
>
Act as another user
</Typography>
</ListItemContent>
</MenuItem>
{isImpersonating && (
<MenuItem
onClick={() => stopImpersonation()}
sx={{
borderRadius: 'var(--joy-radius-sm)',
'&:hover': {
backgroundColor: 'var(--joy-palette-neutral-softHoverBg)',
},
}}
>
<ListItemDecorator
sx={{ color: 'var(--joy-palette-success-500)' }}
>
<Person />
</ListItemDecorator>
<ListItemContent>
<Typography level='body-sm' sx={{ fontWeight: 500 }}>
Stop Impersonating
</Typography>
<Typography
level='body-xs'
sx={{ color: 'var(--joy-palette-text-tertiary)' }}
>
Return to your account
</Typography>
</ListItemContent>
</MenuItem>
)}
<Divider sx={{ my: 1 }} />
</>
)}
<MenuItem
onClick={() => navigate('/settings')}
sx={{
borderRadius: 'var(--joy-radius-sm)',
'&:hover': {
backgroundColor: 'var(--joy-palette-neutral-softHoverBg)',
},
}}
>
<ListItemDecorator sx={{ color: 'var(--joy-palette-neutral-500)' }}>
<Settings />
</ListItemDecorator>
<ListItemContent>
<Typography level='body-sm' sx={{ fontWeight: 500 }}>
Settings
</Typography>
<Typography
level='body-xs'
sx={{ color: 'var(--joy-palette-text-tertiary)' }}
>
Account & preferences
</Typography>
</ListItemContent>
</MenuItem>
<MenuItem
onClick={() => navigate('/settings/circle')}
sx={{
borderRadius: 'var(--joy-radius-sm)',
'&:hover': {
backgroundColor: 'var(--joy-palette-neutral-softHoverBg)',
},
}}
>
<ListItemDecorator sx={{ color: 'var(--joy-palette-primary-500)' }}>
<GroupAdd />
</ListItemDecorator>
<ListItemContent>
<Typography level='body-sm' sx={{ fontWeight: 500 }}>
Invite People
</Typography>
<Typography
level='body-xs'
sx={{ color: 'var(--joy-palette-text-tertiary)' }}
>
Add members to your circle
</Typography>
</ListItemContent>
</MenuItem>
{isLargeScreen && (
<MenuItem
onClick={() => navigate('/settings/detailed#sidepanel')}
sx={{
borderRadius: 'var(--joy-radius-sm)',
'&:hover': {
backgroundColor: 'var(--joy-palette-neutral-softHoverBg)',
},
}}
>
<ListItemDecorator
sx={{ color: 'var(--joy-palette-neutral-500)' }}
>
<Tune />
</ListItemDecorator>
<ListItemContent>
<Typography level='body-sm' sx={{ fontWeight: 500 }}>
Side Panel Settings
</Typography>
<Typography
level='body-xs'
sx={{ color: 'var(--joy-palette-text-tertiary)' }}
>
Customize layout & cards
</Typography>
</ListItemContent>
</MenuItem>
)}
<MenuItem
onClick={handleThemeToggle}
sx={{
borderRadius: 'var(--joy-radius-sm)',
'&:hover': {
backgroundColor: 'var(--joy-palette-neutral-softHoverBg)',
},
}}
>
<ListItemDecorator sx={{ color: 'var(--joy-palette-neutral-500)' }}>
{isDarkMode ? <LightModeOutlined /> : <DarkModeOutlined />}
</ListItemDecorator>
<ListItemContent>
<Typography level='body-sm' sx={{ fontWeight: 500 }}>
{isDarkMode ? 'Switch to Light' : 'Switch to Dark'}
</Typography>
<Typography
level='body-xs'
sx={{ color: 'var(--joy-palette-text-tertiary)' }}
>
Toggle theme appearance
</Typography>
</ListItemContent>
</MenuItem>
{!isPlusUser && (
<MenuItem
onClick={() => navigate('/settings/account')}
sx={{
borderRadius: 'var(--joy-radius-sm)',
'&:hover': {
backgroundColor: 'var(--joy-palette-warning-softHoverBg)',
},
}}
>
<ListItemDecorator
sx={{ color: 'var(--joy-palette-warning-500)' }}
>
<WorkspacePremium />
</ListItemDecorator>
<ListItemContent>
<Typography
level='body-sm'
sx={{
fontWeight: 500,
}}
>
Upgrade to Plus
</Typography>
<Typography level='body-xs'>Unlock premium features</Typography>
</ListItemContent>
</MenuItem>
)}
{/* <MenuItem
onClick={handleSupportEmail}
sx={{
borderRadius: 'var(--joy-radius-sm)',
'&:hover': {
backgroundColor: 'var(--joy-palette-neutral-softHoverBg)',
},
}}
>
<ListItemDecorator sx={{ color: 'var(--joy-palette-info-500)' }}>
<Email />
</ListItemDecorator>
<ListItemContent>
<Typography level='body-sm' sx={{ fontWeight: 500 }}>
Support
</Typography>
<Typography
level='body-xs'
sx={{ color: 'var(--joy-palette-text-tertiary)' }}
>
support@donetick.com
</Typography>
</ListItemContent>
</MenuItem> */}
<Divider sx={{ my: 1 }} />
<MenuItem
onClick={handleLogout}
sx={{
borderRadius: 'var(--joy-radius-sm)',
'&:hover': {
backgroundColor: 'var(--joy-palette-danger-softHoverBg)',
},
}}
>
<ListItemDecorator sx={{ color: 'var(--joy-palette-danger-500)' }}>
<Logout />
</ListItemDecorator>
<ListItemContent>
<Typography
level='body-sm'
sx={{ fontWeight: 500, color: 'var(--joy-palette-danger-500)' }}
>
Logout
</Typography>
</ListItemContent>
</MenuItem>
</Menu>
</Dropdown>
<UserModal
isOpen={isModalOpen}
performers={circleMembersData?.res}
onSelect={user => {
startImpersonation(user, userProfile)
setIsModalOpen(false)
}}
onClose={() => setIsModalOpen(false)}
/>
<SubscriptionModal
open={isSubscriptionModalOpen}
onClose={() => setIsSubscriptionModalOpen(false)}
/>
</>
)
}
export default UserProfileAvatar

View File

@@ -0,0 +1,88 @@
import React from 'react'
import { Box } from '@mui/joy'
import { CSSTransition, TransitionGroup } from 'react-transition-group'
import { useStaggeredAnimation, useReducedMotion } from '../../hooks/useAnimations'
import './PageTransition.css'
const AnimatedList = ({
children,
staggerDelay = 50,
animationType = 'stagger', // 'stagger', 'fade', 'slide'
direction = 'up', // 'up', 'down', 'left', 'right'
renderItem,
keyExtractor,
items,
...boxProps
}) => {
// Handle both children and items patterns
let childrenArray
if (items && renderItem) {
childrenArray = items.map((item, index) =>
React.cloneElement(renderItem(item, index), {
key: keyExtractor ? keyExtractor(item, index) : index
})
)
} else {
childrenArray = React.Children.toArray(children)
}
const visibleItems = useStaggeredAnimation(childrenArray.length, staggerDelay)
const prefersReducedMotion = useReducedMotion()
// If user prefers reduced motion, render without animations
if (prefersReducedMotion) {
return (
<Box {...boxProps}>
{items && renderItem ? childrenArray : children}
</Box>
)
}
const getAnimationClass = () => {
switch (animationType) {
case 'fade':
return 'fade'
case 'slide':
return direction === 'up' ? 'slide-up' : 'page'
case 'stagger':
default:
return 'stagger'
}
}
return (
<Box {...boxProps}>
<TransitionGroup component={null}>
{childrenArray.map((child, index) => {
const isVisible = visibleItems.has(index)
return (
<CSSTransition
key={child.key || index}
in={isVisible}
timeout={{
enter: 300,
exit: 200,
}}
classNames={getAnimationClass()}
unmountOnExit={false}
>
<Box
sx={{
opacity: isVisible ? 1 : 0,
transform: isVisible ? 'none' : 'translateY(20px)',
transition: 'opacity 0.3s ease, transform 0.3s ease',
transitionDelay: `${index * staggerDelay}ms`,
}}
>
{child}
</Box>
</CSSTransition>
)
})}
</TransitionGroup>
</Box>
)
}
export default AnimatedList

View File

@@ -0,0 +1,105 @@
import { Box, CircularProgress, Typography } from '@mui/joy'
import { styled } from '@mui/joy/styles'
// Styled components with keyframe animations
const LoadingContainer = styled(Box)({
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(255, 255, 255, 0.95)',
backdropFilter: 'blur(8px)',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
zIndex: 9999,
animation: 'fadeIn 0.3s ease-out',
'@keyframes fadeIn': {
from: {
opacity: 0,
},
to: {
opacity: 1,
},
},
})
const LoadingContent = styled(Box)({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: '24px',
animation: 'slideUp 0.5s ease-out 0.2s both',
'@keyframes slideUp': {
from: {
opacity: 0,
transform: 'translateY(20px)',
},
to: {
opacity: 1,
transform: 'translateY(0)',
},
},
})
const PulsingText = styled(Typography)({
animation: 'pulse 2s ease-in-out infinite',
'@keyframes pulse': {
'0%, 100%': {
opacity: 1,
},
'50%': {
opacity: 0.5,
},
},
})
const LogoContainer = styled(Box)({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
marginBottom: '24px',
})
const LoadingScreen = ({
message = 'Loading...',
showLogo = true,
size = 'lg',
}) => {
return (
<LoadingContainer>
<LoadingContent>
{showLogo && (
<LogoContainer>
<Typography
level='h1'
sx={{
fontSize: { xs: '2rem', sm: '2.5rem' },
fontWeight: 700,
color: 'primary.500',
mb: 1,
}}
>
Done
<span style={{ color: '#06b6d4' }}>tick</span>
</Typography>
</LogoContainer>
)}
<CircularProgress
size={size}
sx={{
'--CircularProgress-size': size === 'lg' ? '60px' : '40px',
mb: 2,
}}
/>
<PulsingText level='body-md'>{message}</PulsingText>
</LoadingContent>
</LoadingContainer>
)
}
export default LoadingScreen

View File

@@ -0,0 +1,248 @@
/* Page Wrapper */
.page-wrapper {
position: relative;
width: 100%;
min-height: 100vh;
}
/* View Transitions API - Native browser page transitions */
/* These run automatically when the browser supports view transitions */
/* Forward navigation (going deeper) */
::view-transition-old(root):only-child {
animation: slide-out-left 250ms cubic-bezier(0.4, 0, 0.2, 1);
}
::view-transition-new(root):only-child {
animation: slide-in-right 250ms cubic-bezier(0.4, 0, 0.2, 1);
}
/* Back navigation (going up) */
html[data-transition='back']::view-transition-old(root):only-child {
animation: slide-out-right 250ms cubic-bezier(0.4, 0, 0.2, 1);
}
html[data-transition='back']::view-transition-new(root):only-child {
animation: slide-in-left 250ms cubic-bezier(0.4, 0, 0.2, 1);
}
/* Fade for auth pages */
html[data-transition='fade']::view-transition-old(root):only-child,
html[data-transition='fade']::view-transition-new(root):only-child {
animation: fade 200ms ease-in-out;
}
/* Animation keyframes */
@keyframes slide-out-left {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(-30%);
opacity: 0;
}
}
@keyframes slide-in-right {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slide-out-right {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(100%);
opacity: 0;
}
}
@keyframes slide-in-left {
from {
transform: translateX(-30%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes fade {
0%,
100% {
opacity: 0;
}
50% {
opacity: 1;
}
}
/* Modal/overlay animations (still useful for non-route transitions) */
.modal-enter {
opacity: 0;
transform: scale(0.95) translateY(10px);
}
.modal-enter-active {
opacity: 1;
transform: scale(1) translateY(0);
transition:
opacity 250ms ease-out,
transform 250ms ease-out;
}
.modal-exit {
opacity: 1;
transform: scale(1) translateY(0);
}
.modal-exit-active {
opacity: 0;
transform: scale(0.95) translateY(10px);
transition:
opacity 200ms ease-in,
transform 200ms ease-in;
}
/* Slide up animation for bottom sheets/panels */
.slide-up-enter {
opacity: 0;
transform: translateY(100%);
}
.slide-up-enter-active {
opacity: 1;
transform: translateY(0);
transition:
opacity 300ms ease-out,
transform 300ms ease-out;
}
.slide-up-exit {
opacity: 1;
transform: translateY(0);
}
.slide-up-exit-active {
opacity: 0;
transform: translateY(100%);
transition:
opacity 250ms ease-in,
transform 250ms ease-in;
}
/* Loading spinner animation */
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.loading-spinner {
animation: spin 1s linear infinite;
}
/* Skeleton loading animations */
@keyframes skeleton-loading {
0% {
background-position: -200px 0;
}
100% {
background-position: calc(200px + 100%) 0;
}
}
.skeleton {
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200px 100%;
animation: skeleton-loading 1.5s infinite;
}
/* Micro-interactions */
.interactive-element {
transition: all 0.2s ease-out;
transform: translateZ(0); /* Enable GPU acceleration */
}
.interactive-element:hover {
transform: translateY(-2px) translateZ(0);
}
.interactive-element:active {
transform: translateY(0) translateZ(0);
transition: all 0.1s ease-out;
}
/* Stagger animation for lists */
.stagger-enter {
opacity: 0;
transform: translateY(20px);
}
.stagger-enter-active {
opacity: 1;
transform: translateY(0);
transition:
opacity 300ms ease-out,
transform 300ms ease-out;
}
/* Add animation delays for staggered effects */
.stagger-enter-active:nth-child(1) {
transition-delay: 0ms;
}
.stagger-enter-active:nth-child(2) {
transition-delay: 50ms;
}
.stagger-enter-active:nth-child(3) {
transition-delay: 100ms;
}
.stagger-enter-active:nth-child(4) {
transition-delay: 150ms;
}
.stagger-enter-active:nth-child(5) {
transition-delay: 200ms;
}
.stagger-enter-active:nth-child(6) {
transition-delay: 250ms;
}
.stagger-enter-active:nth-child(7) {
transition-delay: 300ms;
}
.stagger-enter-active:nth-child(8) {
transition-delay: 350ms;
}
/* Reduced motion for accessibility */
@media (prefers-reduced-motion: reduce) {
/* Disable View Transitions for users who prefer reduced motion */
::view-transition-old(root),
::view-transition-new(root) {
animation: none !important;
}
.modal-enter,
.modal-enter-active,
.modal-exit,
.modal-exit-active,
.interactive-element,
.stagger-enter,
.stagger-enter-active {
transition: none !important;
animation: none !important;
transform: none !important;
}
}

View File

@@ -0,0 +1,130 @@
import { useLayoutEffect, useRef, useState } from 'react'
import { flushSync } from 'react-dom'
import { useLocation } from 'react-router-dom'
import './PageTransition.css'
// Route hierarchy for determining navigation direction
const routeHierarchy = {
'/': 0,
'/my/chores': 0,
'/chores': 1,
'/chores/create': 2,
'/settings': 1,
'/things': 1,
'/activities': 1,
'/points': 1,
'/labels': 1,
'/projects': 1,
'/login': 0,
'/signup': 1,
'/landing': 0,
'/archived': 1,
}
const getRouteLevel = pathname => {
// Check for exact matches first
if (routeHierarchy[pathname] !== undefined) {
return routeHierarchy[pathname]
}
// Check for dynamic routes (e.g., /chores/123/edit)
if (pathname.includes('/chores/') && pathname.includes('/edit')) {
return 3
}
if (pathname.includes('/chores/') && pathname.includes('/history')) {
return 3
}
if (pathname.includes('/chores/') && pathname.includes('/timer')) {
return 3
}
if (
pathname.includes('/chores/') &&
!pathname.includes('/edit') &&
!pathname.includes('/history') &&
!pathname.includes('/timer')
) {
return 2
}
if (pathname.includes('/things/')) {
return 2
}
if (pathname.includes('/settings/')) {
return 2
}
// Default level
return 1
}
const PageTransition = ({ children }) => {
const location = useLocation()
const prevLevel = useRef(0)
const [displayLocation, setDisplayLocation] = useState(location)
const isFirstRender = useRef(true)
useLayoutEffect(() => {
// Skip transition on first render
if (isFirstRender.current) {
isFirstRender.current = false
setDisplayLocation(location)
prevLevel.current = getRouteLevel(location.pathname)
return
}
// Don't transition if location hasn't actually changed
if (location.pathname === displayLocation.pathname) {
return
}
const currentLevel = getRouteLevel(location.pathname)
const previousLevel = prevLevel.current
// Determine navigation direction
const isBack = currentLevel < previousLevel
const isFade =
location.pathname.includes('/login') ||
location.pathname.includes('/signup') ||
location.pathname.includes('/landing') ||
location.pathname.includes('/auth/')
// Apply transition type as data attribute for CSS
document.documentElement.dataset.transition = isFade
? 'fade'
: isBack
? 'back'
: 'forward'
// Trigger View Transition if supported
if (document.startViewTransition) {
document.startViewTransition(() => {
// flushSync forces React to update the DOM synchronously
// This ensures the View Transition captures the actual DOM change
flushSync(() => {
setDisplayLocation(location)
})
// Scroll to top after DOM update
window.scrollTo({ top: 0, left: 0, behavior: 'instant' })
})
} else {
// Fallback for browsers without View Transitions API
setDisplayLocation(location)
window.scrollTo({ top: 0, left: 0, behavior: 'instant' })
}
// Update refs
prevLevel.current = currentLevel
}, [location, displayLocation.pathname])
return (
<div
className='page-wrapper'
style={{
paddingBottom: `var(--safe-area-inset-bottom, 0px)`,
}}
>
{displayLocation.pathname === location.pathname ? children : null}
</div>
)
}
export default PageTransition

View File

@@ -0,0 +1,138 @@
import { Box, Skeleton } from '@mui/joy'
const SkeletonLoader = ({
type = 'card',
count = 1,
height = 100,
width = '100%',
variant = 'rectangular',
...props
}) => {
const renderSkeleton = () => {
switch (type) {
case 'card':
return (
<Box
sx={{
p: 2,
border: '1px solid',
borderColor: 'divider',
borderRadius: 'md',
}}
>
<Skeleton variant='text' height={24} width='60%' sx={{ mb: 1 }} />
<Skeleton
variant='text'
height={16}
width='100%'
sx={{ mb: 0.5 }}
/>
<Skeleton variant='text' height={16} width='80%' sx={{ mb: 2 }} />
<Box sx={{ display: 'flex', gap: 1 }}>
<Skeleton variant='circular' width={32} height={32} />
<Skeleton variant='rectangular' height={32} width={80} />
</Box>
</Box>
)
case 'list':
return (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2, p: 1.5 }}>
<Skeleton variant='circular' width={40} height={40} />
<Box sx={{ flex: 1 }}>
<Skeleton
variant='text'
height={20}
width='70%'
sx={{ mb: 0.5 }}
/>
<Skeleton variant='text' height={16} width='50%' />
</Box>
<Skeleton variant='rectangular' width={60} height={24} />
</Box>
)
case 'chore':
return (
<Box
sx={{
p: 2,
border: '1px solid',
borderColor: 'divider',
borderRadius: 'md',
}}
>
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'flex-start',
mb: 1,
}}
>
<Skeleton variant='text' height={24} width='50%' />
<Skeleton variant='circular' width={24} height={24} />
</Box>
<Skeleton variant='text' height={16} width='80%' sx={{ mb: 1 }} />
<Box sx={{ display: 'flex', gap: 1, mb: 2 }}>
<Skeleton variant='rectangular' height={20} width={60} />
<Skeleton variant='rectangular' height={20} width={40} />
</Box>
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<Skeleton variant='circular' width={32} height={32} />
<Skeleton variant='text' height={16} width='30%' />
</Box>
</Box>
)
case 'profile':
return (
<Box
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
p: 3,
}}
>
<Skeleton
variant='circular'
width={80}
height={80}
sx={{ mb: 2 }}
/>
<Skeleton variant='text' height={24} width={150} sx={{ mb: 1 }} />
<Skeleton variant='text' height={16} width={100} />
</Box>
)
default:
return (
<Skeleton
variant={variant}
height={height}
width={width}
{...props}
/>
)
}
}
return (
<>
{Array.from({ length: count }, (_, index) => (
<Box key={index} sx={{ mb: type === 'list' ? 0 : 2 }}>
{renderSkeleton()}
</Box>
))}
</>
)
}
export default SkeletonLoader

View File

@@ -0,0 +1,107 @@
import { Button } from '@mui/joy'
import { styled } from '@mui/joy/styles'
const AnimatedButton = styled(Button)(({ theme }) => ({
transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',
transform: 'translateZ(0)', // Enable GPU acceleration
position: 'relative',
overflow: 'hidden',
'&:hover:not(:disabled)': {
transform: 'translateY(-2px) translateZ(0)',
boxShadow: theme.shadow.lg,
},
'&:active:not(:disabled)': {
transform: 'translateY(0) translateZ(0)',
transition: 'all 0.1s cubic-bezier(0.4, 0, 0.2, 1)',
},
'&:focus-visible': {
outline: '2px solid',
outlineColor: theme.palette.primary[500],
outlineOffset: '2px',
},
// Ripple effect
'&::before': {
content: '""',
position: 'absolute',
top: '50%',
left: '50%',
width: '0',
height: '0',
borderRadius: '50%',
background: 'currentColor',
opacity: 0.1,
transform: 'translate(-50%, -50%)',
transition: 'width 0.6s, height 0.6s',
},
'&:active::before': {
width: '300px',
height: '300px',
},
// Loading state
'&[data-loading="true"]': {
pointerEvents: 'none',
position: 'relative',
'& > *': {
opacity: 0.6,
},
'&::after': {
content: '""',
position: 'absolute',
top: '50%',
left: '50%',
width: '16px',
height: '16px',
border: '2px solid currentColor',
borderTop: '2px solid transparent',
borderRadius: '50%',
transform: 'translate(-50%, -50%)',
animation: 'spin 1s linear infinite',
},
},
// Reduced motion support
'@media (prefers-reduced-motion: reduce)': {
transition: 'none',
transform: 'none !important',
'&:hover:not(:disabled)': {
transform: 'none',
},
'&:active:not(:disabled)': {
transform: 'none',
},
'&::before': {
display: 'none',
},
},
}))
const SmoothButton = ({ children, loading = false, onClick, ...props }) => {
const handleClick = event => {
if (loading) return
onClick?.(event)
}
return (
<AnimatedButton
{...props}
onClick={handleClick}
data-loading={loading}
disabled={props.disabled || loading}
>
{children}
</AnimatedButton>
)
}
export default SmoothButton

View File

@@ -0,0 +1,88 @@
import React from 'react'
import { Card } from '@mui/joy'
import { styled } from '@mui/joy/styles'
const AnimatedCard = styled(Card)(({ theme }) => ({
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
transform: 'translateZ(0)', // Enable GPU acceleration
cursor: 'pointer',
position: 'relative',
'&:hover': {
transform: 'translateY(-4px) translateZ(0)',
boxShadow: theme.shadow.lg,
},
'&:active': {
transform: 'translateY(-2px) translateZ(0)',
transition: 'all 0.1s cubic-bezier(0.4, 0, 0.2, 1)',
},
// Subtle background animation on hover
'&::before': {
content: '""',
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
background: 'linear-gradient(45deg, transparent, rgba(255,255,255,0.1), transparent)',
opacity: 0,
transition: 'opacity 0.3s ease',
pointerEvents: 'none',
borderRadius: 'inherit',
},
'&:hover::before': {
opacity: 1,
},
// Focus states for accessibility
'&:focus-visible': {
outline: '2px solid',
outlineColor: theme.palette.primary[500],
outlineOffset: '2px',
},
// Reduced motion support
'@media (prefers-reduced-motion: reduce)': {
transition: 'none',
transform: 'none !important',
'&:hover': {
transform: 'none',
boxShadow: theme.shadow.md, // Still provide visual feedback
},
'&:active': {
transform: 'none',
},
'&::before': {
display: 'none',
},
},
}))
const SmoothCard = ({
children,
onClick,
animationDisabled = false,
...props
}) => {
if (animationDisabled) {
return (
<Card {...props} onClick={onClick}>
{children}
</Card>
)
}
return (
<AnimatedCard {...props} onClick={onClick}>
{children}
</AnimatedCard>
)
}
export default SmoothCard

View File

@@ -0,0 +1,54 @@
import { Box } from '@mui/joy'
import React, { useEffect, useState } from 'react'
import { CSSTransition, TransitionGroup } from 'react-transition-group'
import './PageTransition.css'
const StaggeredList = ({
children,
staggerDelay = 50,
initialDelay = 0,
animate = true,
}) => {
const [isVisible, setIsVisible] = useState(!animate)
useEffect(() => {
if (animate) {
const timer = setTimeout(() => {
setIsVisible(true)
}, initialDelay)
return () => clearTimeout(timer)
}
}, [animate, initialDelay])
if (!animate) {
return <Box>{children}</Box>
}
const childrenArray = React.Children.toArray(children)
return (
<Box>
<TransitionGroup component={null}>
{isVisible &&
childrenArray.map((child, index) => (
<CSSTransition
key={child.key || index}
classNames='stagger'
timeout={{
enter: 300 + index * staggerDelay,
exit: 200,
}}
style={{
transitionDelay: `${index * staggerDelay}ms`,
}}
>
<Box sx={{ mb: 1 }}>{child}</Box>
</CSSTransition>
))}
</TransitionGroup>
</Box>
)
}
export default StaggeredList

View File

@@ -0,0 +1,9 @@
// Animation Components
export { default as AnimatedList } from './AnimatedList'
export { default as PageTransition } from './PageTransition'
export { default as SmoothButton } from './SmoothButton'
export { default as SmoothCard } from './SmoothCard'
export { default as StaggeredList } from './StaggeredList'
// Animation Styles
import './PageTransition.css'

Some files were not shown because too many files have changed in this diff Show More