Compare commits
No commits in common. "6bba18e208fe5fee6c47017a8fbb2de23a6d05f6" and "d9de502894600e7b0062491a7b1d24ed8d5797ea" have entirely different histories.
6bba18e208
...
d9de502894
11 changed files with 27 additions and 200 deletions
|
@ -1,19 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -e
|
|
||||||
if [[ ! -d "/home/amy/code/public/oss/frontend" ]]; then
|
|
||||||
echo "Cannot find source directory; Did you move it?"
|
|
||||||
echo "(Looking for "/home/amy/code/public/oss/frontend")"
|
|
||||||
echo 'Cannot force reload with this script - use "direnv reload" manually and then try again'
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# rebuild the cache forcefully
|
|
||||||
_nix_direnv_force_reload=1 direnv exec "/home/amy/code/public/oss/frontend" true
|
|
||||||
|
|
||||||
# Update the mtime for .envrc.
|
|
||||||
# This will cause direnv to reload again - but without re-building.
|
|
||||||
touch "/home/amy/code/public/oss/frontend/.envrc"
|
|
||||||
|
|
||||||
# Also update the timestamp of whatever profile_rc we have.
|
|
||||||
# This makes sure that we know we are up to date.
|
|
||||||
touch -r "/home/amy/code/public/oss/frontend/.envrc" "/home/amy/code/public/oss/frontend/.direnv"/*.rc
|
|
1
.envrc
1
.envrc
|
@ -1 +0,0 @@
|
||||||
use flake
|
|
|
@ -49,4 +49,4 @@ While maintaining Donetick's commitment to open source, this hosted option will
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under the AGPLv3 License. See the [LICENSE](LICENSE) file for more details. I might consider changing it later to something else
|
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details. I might consider changing it later to something else
|
||||||
|
|
61
flake.lock
generated
61
flake.lock
generated
|
@ -1,61 +0,0 @@
|
||||||
{
|
|
||||||
"nodes": {
|
|
||||||
"flake-parts": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs-lib": "nixpkgs-lib"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1743550720,
|
|
||||||
"narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"rev": "c621e8422220273271f52058f618c94e405bb0f5",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1743583204,
|
|
||||||
"narHash": "sha256-F7n4+KOIfWrwoQjXrL2wD9RhFYLs2/GGe/MQY1sSdlE=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "2c8d3f48d33929642c1c12cd243df4cc7d2ce434",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs-lib": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1743296961,
|
|
||||||
"narHash": "sha256-b1EdN3cULCqtorQ4QeWgLMrd5ZGOjLSLemfa00heasc=",
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "nixpkgs.lib",
|
|
||||||
"rev": "e4822aea2a6d1cdd36653c134cacfd64c97ff4fa",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "nixpkgs.lib",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-parts": "flake-parts",
|
|
||||||
"nixpkgs": "nixpkgs"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": "root",
|
|
||||||
"version": 7
|
|
||||||
}
|
|
23
flake.nix
23
flake.nix
|
@ -1,23 +0,0 @@
|
||||||
{
|
|
||||||
description = "Description for the project";
|
|
||||||
|
|
||||||
inputs = {
|
|
||||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
|
||||||
};
|
|
||||||
|
|
||||||
outputs = inputs@{ flake-parts, ... }:
|
|
||||||
flake-parts.lib.mkFlake { inherit inputs; } {
|
|
||||||
systems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin" ];
|
|
||||||
perSystem = { config, self', inputs', pkgs, system, ... }: {
|
|
||||||
devShells.default = pkgs.mkShell {
|
|
||||||
packages = with pkgs; [
|
|
||||||
nodePackages.npm
|
|
||||||
nodejs
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
flake = {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -179,9 +179,9 @@ export const notInCompletionWindow = chore => {
|
||||||
export const ChoreFilters = userProfile => ({
|
export const ChoreFilters = userProfile => ({
|
||||||
anyone: () => true,
|
anyone: () => true,
|
||||||
assigned_to_me: chore => {
|
assigned_to_me: chore => {
|
||||||
return chore.assignedTo && chore.assignedTo === userProfile?.id
|
return chore.assignedTo && chore.assignedTo === userProfile.id
|
||||||
},
|
},
|
||||||
assigned_to_others: chore => {
|
assigned_to_others: chore => {
|
||||||
return chore.assignedTo && chore.assignedTo !== userProfile?.id
|
return chore.assignedTo && chore.assignedTo !== userProfile.id
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -115,7 +115,7 @@ const LoginView = () => {
|
||||||
Navigate('/forgot-password')
|
Navigate('/forgot-password')
|
||||||
}
|
}
|
||||||
const generateRandomState = () => {
|
const generateRandomState = () => {
|
||||||
const randomState = Math.random().toString(32).substring(5)
|
const randomState = Math.random().toString(36).substring(7)
|
||||||
localStorage.setItem('authState', randomState)
|
localStorage.setItem('authState', randomState)
|
||||||
|
|
||||||
return randomState
|
return randomState
|
||||||
|
|
|
@ -74,7 +74,7 @@ const MyChores = () => {
|
||||||
JSON.parse(localStorage.getItem('openChoreSections')) || {},
|
JSON.parse(localStorage.getItem('openChoreSections')) || {},
|
||||||
)
|
)
|
||||||
const [selectedChoreFilter, setSelectedChoreFilter] = useState(
|
const [selectedChoreFilter, setSelectedChoreFilter] = useState(
|
||||||
localStorage.getItem('selectedChoreFilter') || 'anyone',
|
JSON.parse(localStorage.getItem('selectedChoreFilter')) || 'anyone',
|
||||||
)
|
)
|
||||||
const [searchTerm, setSearchTerm] = useState('')
|
const [searchTerm, setSearchTerm] = useState('')
|
||||||
const [performers, setPerformers] = useState([])
|
const [performers, setPerformers] = useState([])
|
||||||
|
@ -98,12 +98,13 @@ const MyChores = () => {
|
||||||
throw new Error(userProfileResponse.statusText)
|
throw new Error(userProfileResponse.statusText)
|
||||||
}
|
}
|
||||||
Promise.all([
|
Promise.all([
|
||||||
userProfileResponse.json(),
|
|
||||||
choresResponse.json(),
|
choresResponse.json(),
|
||||||
usersResponse.json(),
|
usersResponse.json(),
|
||||||
|
userProfileResponse.json(),
|
||||||
]).then(data => {
|
]).then(data => {
|
||||||
const [userProfileData, choresData, usersData] = data
|
const [choresData, usersData, userProfileData] = data
|
||||||
setUserProfile(userProfileData.res)
|
setUserProfile(userProfileData.res)
|
||||||
|
choresData.res.sort(ChoreSorter)
|
||||||
setChores(choresData.res)
|
setChores(choresData.res)
|
||||||
setFilteredChores(choresData.res)
|
setFilteredChores(choresData.res)
|
||||||
setPerformers(usersData.res)
|
setPerformers(usersData.res)
|
||||||
|
@ -138,11 +139,7 @@ const MyChores = () => {
|
||||||
const sortedChores = choresData.res.sort(ChoreSorter)
|
const sortedChores = choresData.res.sort(ChoreSorter)
|
||||||
setChores(sortedChores)
|
setChores(sortedChores)
|
||||||
setFilteredChores(sortedChores)
|
setFilteredChores(sortedChores)
|
||||||
const sections = ChoresGrouper(
|
const sections = ChoresGrouper(selectedChoreSection, sortedChores)
|
||||||
selectedChoreSection,
|
|
||||||
sortedChores,
|
|
||||||
ChoreFilters(userProfile)[selectedChoreFilter],
|
|
||||||
)
|
|
||||||
setChoreSections(sections)
|
setChoreSections(sections)
|
||||||
if (localStorage.getItem('openChoreSections') === null) {
|
if (localStorage.getItem('openChoreSections') === null) {
|
||||||
setSelectedChoreSectionWithCache(selectedChoreSection)
|
setSelectedChoreSectionWithCache(selectedChoreSection)
|
||||||
|
@ -181,7 +178,7 @@ const MyChores = () => {
|
||||||
}
|
}
|
||||||
const setSelectedChoreFilterWithCache = value => {
|
const setSelectedChoreFilterWithCache = value => {
|
||||||
setSelectedChoreFilter(value)
|
setSelectedChoreFilter(value)
|
||||||
localStorage.setItem('selectedChoreFilter', value)
|
localStorage.setItem('selectedChoreFilter', JSON.stringify(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateChores = newChore => {
|
const updateChores = newChore => {
|
||||||
|
@ -189,13 +186,7 @@ const MyChores = () => {
|
||||||
newChores.push(newChore)
|
newChores.push(newChore)
|
||||||
setChores(newChores)
|
setChores(newChores)
|
||||||
setFilteredChores(newChores)
|
setFilteredChores(newChores)
|
||||||
setChoreSections(
|
setChoreSections(ChoresGrouper(selectedChoreSection, newChores))
|
||||||
ChoresGrouper(
|
|
||||||
selectedChoreSection,
|
|
||||||
newChores,
|
|
||||||
ChoreFilters(userProfile)[selectedChoreFilter],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
setSearchFilter('All')
|
setSearchFilter('All')
|
||||||
}
|
}
|
||||||
const handleMenuOutsideClick = event => {
|
const handleMenuOutsideClick = event => {
|
||||||
|
@ -271,13 +262,7 @@ const MyChores = () => {
|
||||||
}
|
}
|
||||||
setChores(newChores)
|
setChores(newChores)
|
||||||
setFilteredChores(newFilteredChores)
|
setFilteredChores(newFilteredChores)
|
||||||
setChoreSections(
|
setChoreSections(ChoresGrouper(selectedChoreSection, newChores))
|
||||||
ChoresGrouper(
|
|
||||||
selectedChoreSection,
|
|
||||||
newChores,
|
|
||||||
ChoreFilters(userProfile)[selectedChoreFilter],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case 'completed':
|
case 'completed':
|
||||||
|
@ -308,13 +293,7 @@ const MyChores = () => {
|
||||||
)
|
)
|
||||||
setChores(newChores)
|
setChores(newChores)
|
||||||
setFilteredChores(newFilteredChores)
|
setFilteredChores(newFilteredChores)
|
||||||
setChoreSections(
|
setChoreSections(ChoresGrouper(selectedChoreSection, newChores))
|
||||||
ChoresGrouper(
|
|
||||||
selectedChoreSection,
|
|
||||||
newChores,
|
|
||||||
ChoreFilters(userProfile)[selectedChoreFilter],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchOptions = {
|
const searchOptions = {
|
||||||
|
@ -470,11 +449,7 @@ const MyChores = () => {
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
onItemSelect={selected => {
|
onItemSelect={selected => {
|
||||||
const section = ChoresGrouper(
|
const section = ChoresGrouper(selected.value, chores)
|
||||||
selected.value,
|
|
||||||
chores,
|
|
||||||
ChoreFilters(userProfile)[selectedChoreFilter],
|
|
||||||
)
|
|
||||||
setChoreSections(section)
|
setChoreSections(section)
|
||||||
setSelectedChoreSectionWithCache(selected.value)
|
setSelectedChoreSectionWithCache(selected.value)
|
||||||
setOpenChoreSectionsWithCache(
|
setOpenChoreSectionsWithCache(
|
||||||
|
|
|
@ -98,10 +98,6 @@ const NotificationSetting = () => {
|
||||||
const [chatID, setChatID] = useState(
|
const [chatID, setChatID] = useState(
|
||||||
userProfile?.notification_target?.target_id,
|
userProfile?.notification_target?.target_id,
|
||||||
)
|
)
|
||||||
const [webhookURL, setWebhookURL] = useState(
|
|
||||||
userProfile?.notification_target?.target_id,
|
|
||||||
)
|
|
||||||
|
|
||||||
const [error, setError] = useState('')
|
const [error, setError] = useState('')
|
||||||
const SaveValidation = () => {
|
const SaveValidation = () => {
|
||||||
switch (notificationTarget) {
|
switch (notificationTarget) {
|
||||||
|
@ -120,12 +116,6 @@ const NotificationSetting = () => {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case '4':
|
|
||||||
if (webhookURL === '') {
|
|
||||||
setError('Webhook URL is required')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
break
|
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -136,8 +126,7 @@ const NotificationSetting = () => {
|
||||||
if (!SaveValidation()) return
|
if (!SaveValidation()) return
|
||||||
|
|
||||||
UpdateNotificationTarget({
|
UpdateNotificationTarget({
|
||||||
// 4 = Discord
|
target: chatID,
|
||||||
target: notificationTarget === '4' ? webhookURL : chatID,
|
|
||||||
type: Number(notificationTarget),
|
type: Number(notificationTarget),
|
||||||
}).then(resp => {
|
}).then(resp => {
|
||||||
if (resp.status != 200) {
|
if (resp.status != 200) {
|
||||||
|
@ -145,17 +134,6 @@ const NotificationSetting = () => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Discord
|
|
||||||
if (notificationTarget === '4') {
|
|
||||||
setUserProfile({
|
|
||||||
...userProfile,
|
|
||||||
notification_target: {
|
|
||||||
target: webhookURL,
|
|
||||||
type: Number(notificationTarget),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// Others (Telegram)
|
|
||||||
setUserProfile({
|
setUserProfile({
|
||||||
...userProfile,
|
...userProfile,
|
||||||
notification_target: {
|
notification_target: {
|
||||||
|
@ -163,8 +141,6 @@ const NotificationSetting = () => {
|
||||||
type: Number(notificationTarget),
|
type: Number(notificationTarget),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
alert('Notification target updated')
|
alert('Notification target updated')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -347,7 +323,7 @@ const NotificationSetting = () => {
|
||||||
<Typography level='h3'>Custom Notification</Typography>
|
<Typography level='h3'>Custom Notification</Typography>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Typography level='body-md'>
|
<Typography level='body-md'>
|
||||||
Notification through other platform like Telegram or Pushover
|
Notificaiton through other platform like Telegram or Pushover
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<FormControl orientation='horizontal'>
|
<FormControl orientation='horizontal'>
|
||||||
|
@ -404,7 +380,6 @@ const NotificationSetting = () => {
|
||||||
<Option value='0'>None</Option>
|
<Option value='0'>None</Option>
|
||||||
<Option value='1'>Telegram</Option>
|
<Option value='1'>Telegram</Option>
|
||||||
<Option value='2'>Pushover</Option>
|
<Option value='2'>Pushover</Option>
|
||||||
<Option value='4'>Discord</Option>
|
|
||||||
<Option value='3'>Webhooks</Option>
|
<Option value='3'>Webhooks</Option>
|
||||||
</Select>
|
</Select>
|
||||||
{notificationTarget === '1' && (
|
{notificationTarget === '1' && (
|
||||||
|
@ -463,19 +438,6 @@ const NotificationSetting = () => {
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{notificationTarget === '4' && (
|
|
||||||
<>
|
|
||||||
<Typography level='body-sm'>Webhook URL</Typography>
|
|
||||||
<Input
|
|
||||||
value={webhookURL}
|
|
||||||
onChange={e => setWebhookURL(e.target.value)}
|
|
||||||
placeholder='Webhook URL'
|
|
||||||
sx={{
|
|
||||||
width: '200px',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{error && (
|
{error && (
|
||||||
<Typography color='warning' level='body-sm'>
|
<Typography color='warning' level='body-sm'>
|
||||||
{error}
|
{error}
|
||||||
|
|
|
@ -430,18 +430,12 @@ const TaskInput = ({ autoFocus, onChoreUpdate }) => {
|
||||||
assignedTo: userProfile.id,
|
assignedTo: userProfile.id,
|
||||||
assignStrategy: 'random',
|
assignStrategy: 'random',
|
||||||
isRolling: false,
|
isRolling: false,
|
||||||
notification: true,
|
notification: false,
|
||||||
description: description || null,
|
description: description || null,
|
||||||
labelsV2: [],
|
labelsV2: [],
|
||||||
priority: priority || 0,
|
priority: priority || 0,
|
||||||
status: 0,
|
status: 0,
|
||||||
frequencyType: 'once',
|
frequencyType: 'once',
|
||||||
frequencyMetadata: {},
|
|
||||||
notificationMetadata: {
|
|
||||||
dueDate: true,
|
|
||||||
predue: true,
|
|
||||||
nagging: true
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frequency) {
|
if (frequency) {
|
||||||
|
|
|
@ -105,12 +105,12 @@ const NavBar = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className='flex gap-2 p-3'>
|
<nav className='flex gap-2 p-2'>
|
||||||
<IconButton size='md' variant='plain' onClick={() => setDrawerOpen(true)}>
|
<IconButton size='sm' variant='plain' onClick={() => setDrawerOpen(true)}>
|
||||||
<MenuRounded />
|
<MenuRounded />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Box
|
<Box
|
||||||
className='flex items-center gap-2'
|
className='flex items-center gap-1'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigate('/my/chores')
|
navigate('/my/chores')
|
||||||
}}
|
}}
|
||||||
|
|
Loading…
Add table
Reference in a new issue