diff --git a/src/utils/TokenManager.jsx b/src/utils/TokenManager.jsx index 58536ca..1c6d651 100644 --- a/src/utils/TokenManager.jsx +++ b/src/utils/TokenManager.jsx @@ -1,55 +1,52 @@ import Cookies from 'js-cookie' import { API_URL } from '../Config' -import { login, RefreshToken } from './Fetcher' +import { RefreshToken } from './Fetcher' import { Preferences } from '@capacitor/preferences' class ApiManager { - constructor(){ + constructor() { this.customServerURL = API_URL this.initialized = false } - async init(){ - if(this.initialized){ + async init() { + if (this.initialized) { return } - const { value: serverURL } = await Preferences.get({ key: 'customServerUrl' }); - + const { value: serverURL } = await Preferences.get({ + key: 'customServerUrl', + }) + this.customServerURL = serverURL || this.apiURL this.initialized = true - - } - getApiURL(){ + getApiURL() { return this.customServerURL } - updateApiURL(url){ + updateApiURL(url) { this.customServerURL = url } } - -export const apiManager = new ApiManager(); - +export const apiManager = new ApiManager() export function Fetch(url, options) { - if (!isTokenValid()) { // store current location in cookie - Cookies.set('ca_redirect', window.location.pathname); + Cookies.set('ca_redirect', window.location.pathname) // Assuming you have a function isTokenValid() that checks token validity - window.location.href = '/login'; // Redirect to login page + window.location.href = '/login' // Redirect to login page // return Promise.reject("Token is not valid"); } if (!options) { - options = {}; + options = {} } - options.headers = { ...options.headers, ...HEADERS() }; + options.headers = { ...options.headers, ...HEADERS() } - const baseURL = apiManager.getApiURL(); + const baseURL = apiManager.getApiURL() - const fullURL = `${baseURL}${url}`; - return fetch(fullURL, options); + const fullURL = `${baseURL}${url}` + return fetch(fullURL, options) } export const HEADERS = () => { @@ -81,8 +78,7 @@ export const isTokenValid = () => { } export const refreshAccessToken = () => { - RefreshToken() - .then(res => { + RefreshToken().then(res => { if (res.status === 200) { res.json().then(data => { localStorage.setItem('ca_token', data.token) diff --git a/src/views/Settings/NotificationSetting.jsx b/src/views/Settings/NotificationSetting.jsx index 728cf2b..7894576 100644 --- a/src/views/Settings/NotificationSetting.jsx +++ b/src/views/Settings/NotificationSetting.jsx @@ -1,13 +1,30 @@ -import { Box, Button, Card, Checkbox, Divider, FormControl, FormHelperText, FormLabel, IconButton, Input, List, ListItem, Option, Select, Snackbar, Switch, Typography } from '@mui/joy' +import { Capacitor } from '@capacitor/core' +import { LocalNotifications } from '@capacitor/local-notifications' +import { Preferences } from '@capacitor/preferences' +import { Close } from '@mui/icons-material' +import { + Box, + Button, + Card, + Divider, + FormControl, + FormHelperText, + FormLabel, + IconButton, + Input, + Option, + Select, + Snackbar, + Switch, + Typography, +} from '@mui/joy' import React, { useContext, useEffect, useState } from 'react' import { UserContext } from '../../contexts/UserContext' -import { GetUserProfile, UpdateUserDetails } from '../../utils/Fetcher' -import { Capacitor } from '@capacitor/core' -import { Preferences } from '@capacitor/preferences' -import { LocalNotifications } from '@capacitor/local-notifications' -import { Close } from '@mui/icons-material' -import { PushNotifications } from '@capacitor/push-notifications' -import { UpdateNotificationTarget } from '../../utils/Fetcher' +import { + GetUserProfile, + UpdateNotificationTarget, + UpdateUserDetails, +} from '../../utils/Fetcher' const NotificationSetting = () => { const [isSnackbarOpen, setIsSnackbarOpen] = useState(false) @@ -23,52 +40,55 @@ const NotificationSetting = () => { } }, []) const getNotificationPreferences = async () => { - const ret = await Preferences.get({ key: 'notificationPreferences' }); - return JSON.parse(ret.value); - }; - const setNotificationPreferences = async (value) => { - if (value.granted === false){ - await Preferences.set({ key: 'notificationPreferences', value: JSON.stringify({ granted: false }) }); + const ret = await Preferences.get({ key: 'notificationPreferences' }) + return JSON.parse(ret.value) + } + const setNotificationPreferences = async value => { + if (value.granted === false) { + await Preferences.set({ + key: 'notificationPreferences', + value: JSON.stringify({ granted: false }), + }) return } - const currentSettings = await getNotificationPreferences(); - await Preferences.set({ key: 'notificationPreferences', value: JSON.stringify({ ...currentSettings, ...value }) }); - }; + const currentSettings = await getNotificationPreferences() + await Preferences.set({ + key: 'notificationPreferences', + value: JSON.stringify({ ...currentSettings, ...value }), + }) + } const getPushNotificationPreferences = async () => { - const ret = await Preferences.get({ key: 'pushNotificationPreferences' }); - return JSON.parse(ret.value); - }; + const ret = await Preferences.get({ key: 'pushNotificationPreferences' }) + return JSON.parse(ret.value) + } + + const setPushNotificationPreferences = async value => { + await Preferences.set({ + key: 'pushNotificationPreferences', + value: JSON.stringify(value), + }) + } + + const [deviceNotification, setDeviceNotification] = useState(false) - const setPushNotificationPreferences = async (value) => { - await Preferences.set({ key: 'pushNotificationPreferences', value: JSON.stringify(value) }); - }; - - const [deviceNotification, setDeviceNotification] = useState( - false - ) - const [dueNotification, setDueNotification] = useState(true) const [preDueNotification, setPreDueNotification] = useState(false) const [naggingNotification, setNaggingNotification] = useState(false) - const [pushNotification, setPushNotification] = useState( - false - ) - + const [pushNotification, setPushNotification] = useState(false) + useEffect(() => { - getNotificationPreferences().then((resp) => { + getNotificationPreferences().then(resp => { setDeviceNotification(resp.granted) setDueNotification(resp.dueNotification) setPreDueNotification(resp.preDueNotification) setNaggingNotification(resp.naggingNotification) - } - ) - getPushNotificationPreferences().then((resp) => { + }) + getPushNotificationPreferences().then(resp => { setPushNotification(resp.granted) - } - ) + }) }, []) - + const [notificationTarget, setNotificationTarget] = useState( userProfile?.notification_target ? String(userProfile.notification_target.type) @@ -126,100 +146,104 @@ const NotificationSetting = () => { Manage your Device Notificaiton -
- Device Notification - {Capacitor.isNativePlatform()? 'Receive notification on your device when a task is due' : 'This feature is only available on mobile devices'} -
- { - event.preventDefault() - if (deviceNotification === false){ - LocalNotifications.requestPermissions().then((resp) => { - if (resp.display === 'granted') { - - setDeviceNotification(true) - setNotificationPreferences({granted: true}) - } - else if (resp.display === 'denied') { - setIsSnackbarOpen(true) - setDeviceNotification(false) - setNotificationPreferences({granted: false}) - } - }) - } - else{ - setDeviceNotification(false) - } - } - } - color={deviceNotification ? 'success' : 'neutral'} - variant={deviceNotification ? 'solid' : 'outlined'} - endDecorator={deviceNotification ? 'On' : 'Off'} - slotProps={{ - endDecorator: { - sx: { - minWidth: 24, + orientation='horizontal' + sx={{ width: 400, justifyContent: 'space-between' }} + > +
+ Device Notification + + {Capacitor.isNativePlatform() + ? 'Receive notification on your device when a task is due' + : 'This feature is only available on mobile devices'}{' '} + +
+ { + event.preventDefault() + if (deviceNotification === false) { + LocalNotifications.requestPermissions().then(resp => { + if (resp.display === 'granted') { + setDeviceNotification(true) + setNotificationPreferences({ granted: true }) + } else if (resp.display === 'denied') { + setIsSnackbarOpen(true) + setDeviceNotification(false) + setNotificationPreferences({ granted: false }) + } + }) + } else { + setDeviceNotification(false) + } + }} + color={deviceNotification ? 'success' : 'neutral'} + variant={deviceNotification ? 'solid' : 'outlined'} + endDecorator={deviceNotification ? 'On' : 'Off'} + slotProps={{ + endDecorator: { + sx: { + minWidth: 24, + }, }, - }, - }} - /> -
-{deviceNotification && ( - - {[ - { - 'title': 'Due Date Notification', - 'checked': dueNotification, - 'set': setDueNotification, - 'label': 'Notification when the task is due', - 'property': 'dueNotification', - 'disabled': false - }, - { - 'title': 'Pre-Due Date Notification', - 'checked': preDueNotification, - 'set': setPreDueNotification, - 'label': 'Notification a few hours before the task is due', - 'property': 'preDueNotification', - 'disabled': true - }, - { - 'title': 'Overdue Notification', - 'checked': naggingNotification, - 'set': setNaggingNotification, - 'label': 'Notification when the task is overdue', - 'property': 'naggingNotification', - 'disabled': true - } -] - .map(item => ( - -
- {item.title} - {item.label} -
+ }} + /> +
+ {deviceNotification && ( + + {[ + { + title: 'Due Date Notification', + checked: dueNotification, + set: setDueNotification, + label: 'Notification when the task is due', + property: 'dueNotification', + disabled: false, + }, + { + title: 'Pre-Due Date Notification', + checked: preDueNotification, + set: setPreDueNotification, + label: 'Notification a few hours before the task is due', + property: 'preDueNotification', + disabled: true, + }, + { + title: 'Overdue Notification', + checked: naggingNotification, + set: setNaggingNotification, + label: 'Notification when the task is overdue', + property: 'naggingNotification', + disabled: true, + }, + ].map(item => ( + +
+ {item.title} + {item.label} +
- { - setNotificationPreferences({[item.property]: !item.checked}) - item.set(!item.checked) - }} - color={item.checked ? 'success' : ''} - variant='solid' endDecorator={item.checked ? 'On' : 'Off'} slotProps={{ endDecorator: { sx: { minWidth: 24 } } }} /> -
- ))} -
-)} - {/* { + setNotificationPreferences({ [item.property]: !item.checked }) + item.set(!item.checked) + }} + color={item.checked ? 'success' : ''} + variant='solid' + endDecorator={item.checked ? 'On' : 'Off'} + slotProps={{ endDecorator: { sx: { minWidth: 24 } } }} + /> + + ))} +
+ )} + {/* @@ -267,180 +291,194 @@ const NotificationSetting = () => { /> */} - + onClick={() => { + // schedule a local notification in 5 seconds + LocalNotifications.schedule({ + notifications: [ + { + title: 'Task Reminder', + body: 'You have a task due soon', + id: 1, + schedule: { at: new Date(Date.now() + 3000) }, + sound: null, + attachments: null, + actionTypeId: '', + extra: null, + }, + ], + }) + }} + > + Test Notification{' '} + Custom Notification - Notificaiton through other platform like Telegram or Pushover - - - -
- Custom Notification - Receive notification on other platform -
- { - event.preventDefault() - if (chatID !== 0){ - setChatID(0) - } - else{ - setChatID('') - UpdateUserDetails({ - chatID: Number(0), - }).then(resp => { - resp.json().then(data => { - setUserProfile(data) - }) - }) - } - setNotificationTarget('0') - handleSave() - - } - - } - color={chatID!==0 ? 'success' : 'neutral'} - variant={chatID!==0 ? 'solid' : 'outlined'} - endDecorator={chatID!==0 ? 'On' : 'Off'} - slotProps={{ - endDecorator: { - sx: { - minWidth: 24, - }, - }, - }} - /> -
- {chatID !== 0&& ( - - - - {notificationTarget === '1' && ( - <> - - You need to initiate a message to the bot in order for the Telegram - notification to work{' '} - - Click here - {' '} - to start a chat - - - Chat ID - - setChatID(e.target.value)} - placeholder='User ID / Chat ID' - sx={{ - width: '200px', - }} - /> - - If you don't know your Chat ID, start chat with userinfobot and it - will send you your Chat ID.{' '} - - Click here - {' '} - to start chat with userinfobot{' '} - - - )} - {notificationTarget === '2' && ( - <> - User key - setChatID(e.target.value)} - placeholder='User ID' - sx={{ - width: '200px', - }} - /> - - )} - {error && ( - - {error} - - )} - - - - )} - setIsSnackbarOpen(false)} endDecorator={ setIsSnackbarOpen(false)}>}> -
- Permission Denied - You have denied the permission to receive notification on this device. Please enable it in your device settings + Notificaiton through other platform like Telegram or Pushover -
-
+ + +
+ Custom Notification + + Receive notification on other platform + +
+ { + event.preventDefault() + if (chatID !== 0) { + setChatID(0) + } else { + setChatID('') + UpdateUserDetails({ + chatID: Number(0), + }).then(resp => { + resp.json().then(data => { + setUserProfile(data) + }) + }) + } + setNotificationTarget('0') + handleSave() + }} + color={chatID !== 0 ? 'success' : 'neutral'} + variant={chatID !== 0 ? 'solid' : 'outlined'} + endDecorator={chatID !== 0 ? 'On' : 'Off'} + slotProps={{ + endDecorator: { + sx: { + minWidth: 24, + }, + }, + }} + /> +
+ {chatID !== 0 && ( + + + {notificationTarget === '1' && ( + <> + + You need to initiate a message to the bot in order for the + Telegram notification to work{' '} + + Click here + {' '} + to start a chat + + + Chat ID + + setChatID(e.target.value)} + placeholder='User ID / Chat ID' + sx={{ + width: '200px', + }} + /> + + If you don't know your Chat ID, start chat with userinfobot and + it will send you your Chat ID.{' '} + + Click here + {' '} + to start chat with userinfobot{' '} + + + )} + {notificationTarget === '2' && ( + <> + User key + setChatID(e.target.value)} + placeholder='User ID' + sx={{ + width: '200px', + }} + /> + + )} + {error && ( + + {error} + + )} + + + + )} + setIsSnackbarOpen(false)} + endDecorator={ + setIsSnackbarOpen(false)}> + + + } + > +
+ Permission Denied + + You have denied the permission to receive notification on this + device. Please enable it in your device settings + +
+
) } diff --git a/vite.config.js b/vite.config.js index f8e9fde..6d6044b 100644 --- a/vite.config.js +++ b/vite.config.js @@ -61,6 +61,7 @@ export default defineConfig({ workbox: { skipWaiting: true, // Force the waiting service worker to become the active service worker clientsClaim: true, // Take control of uncontrolled clients as soon as the service worker becomes active + maximumFileSizeToCacheInBytes: 6000000, // 6MB }, }), ],