add arhived

This commit is contained in:
Romulus21
2022-01-18 19:07:54 +01:00
parent 4e0fa8d0e5
commit 021848b543
8 changed files with 63 additions and 34 deletions

View File

@@ -1 +1 @@
[{"timestamp":1642349922889,"files":[{"filename":"bundle.e3489.css","previous":2808,"size":0,"diff":-2808},{"filename":"bundle.*****.esm.js","previous":10272,"size":10269,"diff":-3},{"filename":"polyfills.*****.esm.js","previous":2191,"size":2191,"diff":0},{"filename":"route-Home.chunk.*****.esm.js","previous":5325,"size":5318,"diff":-7},{"filename":"route-Plant.chunk.*****.esm.js","previous":6411,"size":6423,"diff":12},{"filename":"route-Profile.chunk.*****.esm.js","previous":922,"size":922,"diff":0},{"filename":"sw-esm.js","previous":10767,"size":10764,"diff":-3},{"filename":"sw.js","previous":10760,"size":10774,"diff":14},{"filename":"bundle.e98ad.js","previous":10911,"size":0,"diff":-10911},{"filename":"polyfills.03377.js","previous":2291,"size":0,"diff":-2291},{"filename":"route-Home.chunk.58d66.js","previous":5871,"size":0,"diff":-5871},{"filename":"route-Plant.chunk.b4421.js","previous":7001,"size":0,"diff":-7001},{"filename":"route-Profile.chunk.5b010.js","previous":1393,"size":0,"diff":-1393},{"filename":"index.html","previous":1751,"size":1750,"diff":-1},{"filename":"200.html","previous":908,"size":907,"diff":-1},{"filename":"bundle.6e91b.css","previous":0,"size":2808,"diff":2808},{"filename":"route-Home~route-Plant.chunk.f4501.js","previous":0,"size":5268,"diff":5268},{"filename":"bundle.bf6f7.js","previous":0,"size":10941,"diff":10941},{"filename":"polyfills.0ba84.js","previous":0,"size":2290,"diff":2290},{"filename":"route-Home.chunk.04c91.js","previous":0,"size":1432,"diff":1432},{"filename":"route-Plant.chunk.445a5.js","previous":0,"size":3029,"diff":3029},{"filename":"route-Profile.chunk.3423a.js","previous":0,"size":1394,"diff":1394}]},{"timestamp":1642348996263,"files":[{"filename":"ssr-build/ssr-bundle.f564d.css","previous":5645,"size":0,"diff":-5645},{"filename":"ssr-build/ssr-bundle.js","previous":12645,"size":0,"diff":-12645},{"filename":"bundle.e3489.css","previous":0,"size":2808,"diff":2808},{"filename":"bundle.*****.esm.js","previous":0,"size":10272,"diff":10272},{"filename":"polyfills.*****.esm.js","previous":0,"size":2191,"diff":2191},{"filename":"route-Home.chunk.*****.esm.js","previous":0,"size":5325,"diff":5325},{"filename":"route-Plant.chunk.*****.esm.js","previous":0,"size":6411,"diff":6411},{"filename":"route-Profile.chunk.*****.esm.js","previous":0,"size":922,"diff":922},{"filename":"sw-esm.js","previous":0,"size":10767,"diff":10767},{"filename":"sw.js","previous":0,"size":10760,"diff":10760},{"filename":"bundle.e98ad.js","previous":0,"size":10911,"diff":10911},{"filename":"polyfills.03377.js","previous":0,"size":2291,"diff":2291},{"filename":"route-Home.chunk.58d66.js","previous":0,"size":5871,"diff":5871},{"filename":"route-Plant.chunk.b4421.js","previous":0,"size":7001,"diff":7001},{"filename":"route-Profile.chunk.5b010.js","previous":0,"size":1393,"diff":1393},{"filename":"index.html","previous":0,"size":1751,"diff":1751},{"filename":"200.html","previous":0,"size":908,"diff":908}]}]
[{"timestamp":1642514633677,"files":[{"filename":"bundle.*****.esm.js","previous":10269,"size":10271,"diff":2},{"filename":"polyfills.*****.esm.js","previous":2191,"size":2191,"diff":0},{"filename":"route-Home.chunk.*****.esm.js","previous":5318,"size":5604,"diff":286},{"filename":"route-Plant.chunk.*****.esm.js","previous":6423,"size":6752,"diff":329},{"filename":"route-Profile.chunk.*****.esm.js","previous":922,"size":922,"diff":0},{"filename":"sw-esm.js","previous":10764,"size":10763,"diff":-1},{"filename":"sw.js","previous":10774,"size":10769,"diff":-5},{"filename":"index.html","previous":1750,"size":1749,"diff":-1},{"filename":"200.html","previous":907,"size":906,"diff":-1},{"filename":"bundle.6e91b.css","previous":2808,"size":0,"diff":-2808},{"filename":"route-Home~route-Plant.chunk.f4501.js","previous":5268,"size":0,"diff":-5268},{"filename":"bundle.bf6f7.js","previous":10941,"size":0,"diff":-10941},{"filename":"polyfills.0ba84.js","previous":2290,"size":2290,"diff":0},{"filename":"route-Home.chunk.04c91.js","previous":1432,"size":0,"diff":-1432},{"filename":"route-Plant.chunk.445a5.js","previous":3029,"size":0,"diff":-3029},{"filename":"route-Profile.chunk.3423a.js","previous":1394,"size":1394,"diff":0},{"filename":"bundle.fdcd5.css","previous":0,"size":2890,"diff":2890},{"filename":"route-Home~route-Plant.chunk.7dea9.js","previous":0,"size":5510,"diff":5510},{"filename":"bundle.af5c1.js","previous":0,"size":10940,"diff":10940},{"filename":"route-Home.chunk.1a164.js","previous":0,"size":1508,"diff":1508},{"filename":"route-Plant.chunk.d2bd9.js","previous":0,"size":3152,"diff":3152}]},{"timestamp":1642349922889,"files":[{"filename":"bundle.e3489.css","previous":2808,"size":0,"diff":-2808},{"filename":"bundle.*****.esm.js","previous":10272,"size":10269,"diff":-3},{"filename":"polyfills.*****.esm.js","previous":2191,"size":2191,"diff":0},{"filename":"route-Home.chunk.*****.esm.js","previous":5325,"size":5318,"diff":-7},{"filename":"route-Plant.chunk.*****.esm.js","previous":6411,"size":6423,"diff":12},{"filename":"route-Profile.chunk.*****.esm.js","previous":922,"size":922,"diff":0},{"filename":"sw-esm.js","previous":10767,"size":10764,"diff":-3},{"filename":"sw.js","previous":10760,"size":10774,"diff":14},{"filename":"bundle.e98ad.js","previous":10911,"size":0,"diff":-10911},{"filename":"polyfills.03377.js","previous":2291,"size":0,"diff":-2291},{"filename":"route-Home.chunk.58d66.js","previous":5871,"size":0,"diff":-5871},{"filename":"route-Plant.chunk.b4421.js","previous":7001,"size":0,"diff":-7001},{"filename":"route-Profile.chunk.5b010.js","previous":1393,"size":0,"diff":-1393},{"filename":"index.html","previous":1751,"size":1750,"diff":-1},{"filename":"200.html","previous":908,"size":907,"diff":-1},{"filename":"bundle.6e91b.css","previous":0,"size":2808,"diff":2808},{"filename":"route-Home~route-Plant.chunk.f4501.js","previous":0,"size":5268,"diff":5268},{"filename":"bundle.bf6f7.js","previous":0,"size":10941,"diff":10941},{"filename":"polyfills.0ba84.js","previous":0,"size":2290,"diff":2290},{"filename":"route-Home.chunk.04c91.js","previous":0,"size":1432,"diff":1432},{"filename":"route-Plant.chunk.445a5.js","previous":0,"size":3029,"diff":3029},{"filename":"route-Profile.chunk.3423a.js","previous":0,"size":1394,"diff":1394}]},{"timestamp":1642348996263,"files":[{"filename":"ssr-build/ssr-bundle.f564d.css","previous":5645,"size":0,"diff":-5645},{"filename":"ssr-build/ssr-bundle.js","previous":12645,"size":0,"diff":-12645},{"filename":"bundle.e3489.css","previous":0,"size":2808,"diff":2808},{"filename":"bundle.*****.esm.js","previous":0,"size":10272,"diff":10272},{"filename":"polyfills.*****.esm.js","previous":0,"size":2191,"diff":2191},{"filename":"route-Home.chunk.*****.esm.js","previous":0,"size":5325,"diff":5325},{"filename":"route-Plant.chunk.*****.esm.js","previous":0,"size":6411,"diff":6411},{"filename":"route-Profile.chunk.*****.esm.js","previous":0,"size":922,"diff":922},{"filename":"sw-esm.js","previous":0,"size":10767,"diff":10767},{"filename":"sw.js","previous":0,"size":10760,"diff":10760},{"filename":"bundle.e98ad.js","previous":0,"size":10911,"diff":10911},{"filename":"polyfills.03377.js","previous":0,"size":2291,"diff":2291},{"filename":"route-Home.chunk.58d66.js","previous":0,"size":5871,"diff":5871},{"filename":"route-Plant.chunk.b4421.js","previous":0,"size":7001,"diff":7001},{"filename":"route-Profile.chunk.5b010.js","previous":0,"size":1393,"diff":1393},{"filename":"index.html","previous":0,"size":1751,"diff":1751},{"filename":"200.html","previous":0,"size":908,"diff":908}]}]

View File

@@ -10,10 +10,10 @@ export default function ContextsProviders({children}) {
const [data, setData] = useLocalStorage('data', {})
const [user, setUser] = useUser(data, setData)
const {plants, addPlant, editPlant, removePlant, addAction, doneTask, history} = usePlants(data, setData)
const {plants, addPlant, editPlant, removePlant, addAction, doneTask, history, archivedEntries} = usePlants(data, setData)
return <UserContext.Provider value={[user, setUser]}>
<PlantsContext.Provider value={{plants, addPlant, editPlant, removePlant, addAction, doneTask, history}}>
<PlantsContext.Provider value={{plants, addPlant, editPlant, removePlant, addAction, doneTask, history, archivedEntries}}>
{children}
</PlantsContext.Provider>
</UserContext.Provider>

View File

@@ -1,5 +1,6 @@
import { useEffect, useState } from "preact/hooks"
import {route} from "preact-router";
import {actionId} from "../utilities/actions";
const usePlants = (data, setData) => {
const [plants, setPlants] = useState([])
@@ -42,32 +43,28 @@ const usePlants = (data, setData) => {
setData({...data, plants: plants})
}
const doneTask = (actionId) => {
const doneTask = (action) => {
let history = data.history ?? {}
history[actionId] = new Date()
setData({...data, history: history})
notifyMe()
history[action] = new Date()
let archived = data.archived ?? []
archived.push({
plantId: Number(action.split('-')[1]),
action: actionId(action.split('-')[0]),
time: (new Date()).toSQLDate()
})
setData({...data, history: history, archived: archived})
}
const history = () => data.history ?? {}
const notifyMe = () => {
if (!('Notification' in window)) {
alert('Ce navigateur ne prend pas en charge la notification de bureau')
} else if (Notification.permission === 'granted') {
// Si tout va bien, créons une notification
const notification = new Notification('Salut toi!')
} else if (Notification.permission !== 'denied') {
Notification.requestPermission().then((permission) => {
// Si l'utilisateur accepte, créons une notification
if (permission === 'granted') {
const notification = new Notification('Salut toi!')
}
})
}
const archivedEntries = (plantId) => {
let archived = data.archived ?? []
return archived.where('plantId', plantId)
}
return {plants, addPlant, editPlant, removePlant, addAction, doneTask, history}
return {plants, addPlant, editPlant, removePlant, addAction, doneTask, history, archivedEntries}
}
export default usePlants

View File

@@ -20,4 +20,14 @@ Date.prototype.toSQLDate = function() {
return `${this.getFullYear()}-${Number(this.getMonth() + 1).pad(2)}-${Number(this.getDate()).pad(2)}`
}
/**
* Filter array on a field common of the objects
* @param {string} field to filter
* @param {string} search to filter by
* @returns {*[]}
*/
Array.prototype.where = function(field, search) {
return this.filter(item => item[field] === search)
}
export default App;

View File

@@ -30,7 +30,7 @@ export const Home = () => {
</div>
<div className="w-full sticky bottom-5 flex justify-end">
<div onClick={() => setAddModal(true)}
className="rounded-full w-16 h-16 flex items-center justify-center cursor-pointer bg-green-800 hover-bg-green-900 text-white">
className="rounded-full shadow w-16 h-16 flex items-center justify-center cursor-pointer bg-green-800 hover-bg-green-900 text-white">
Add +
</div>
</div>

View File

@@ -9,24 +9,23 @@ import {getPicture, storePicture} from "../utilities/pictures"
import {EditSVG, PlusSVG} from "../components/SVG"
import {classNames} from "../utilities/classNames"
import {PlantForm} from "../components/Plants"
import {ACTION_TYPES, actionId} from "../utilities/actions"
const Plant = ({id}) => {
const [addModal, setAddModal] = useState(false)
const [editModal, setEditModal] = useState(false)
const [deleteModal, setDeleteModal] = useState(false)
const {plants, editPlant, removePlant, addAction, doneTask, history} = useContext(PlantsContext)
const {plants, editPlant, removePlant, addAction, doneTask, history, archivedEntries} = useContext(PlantsContext)
const [plant, setPlant] = useState({})
const archived = archivedEntries(Number(id))
const [actionForm, setActionForm] = useState({})
const [image, setImage] = useState(localStorage.getItem("image" + id) ?? '')
const pictureName = 'picture-' + id
const picture = useRef(null)
const action_types = ['watering', 'spraying', 'bathing']
useEffect(() => {
const plantFind = plants.find(plant => plant.id === Number(id))
console.log(plantFind, plantFind['indoor'])
setPlant(plantFind)
}, [])
@@ -38,7 +37,7 @@ const Plant = ({id}) => {
e.preventDefault()
e.stopPropagation()
if (!actionForm.action_type) {
actionForm.action_type = action_types[0]
actionForm.action_type = ACTION_TYPES[0]
}
addAction(plant, actionForm)
setAddModal(false)
@@ -78,14 +77,15 @@ const Plant = ({id}) => {
</div>
<div className="flex-1">
{plant.description && <p>{ plant.description }</p>}
{/*{plant.hasAttribute('indoor') && <p>{ plant.indoor ? 'Indoor' : 'Outdoor' }</p>}*/}
{plant.hasOwnProperty('indoor') && <span className="inline-block bg-green-500 text-white px-2 py-1 text-sm font-semibold rounded shadow my-2">{ plant.indoor ? 'Indoor' : 'Outdoor' }</span>}
{plant.spot && <p>Spot: <span className="font-bold">{ plant.spot }</span></p>}
</div>
</div>
<div>
<div className="flex items-center gap-2">
<h2>Actions</h2>
<SmallButton className="bg-blue-500 hover:bg-blue-700 mb-2 mt-5" onClick={() => setAddModal(true)}>
<SmallButton className="bg-blue-500 hover:bg-blue-700 mb-2 mt-5"
onClick={() => setAddModal(true)}>
<PlusSVG className="w-4 h-4" />
</SmallButton>
</div>
@@ -98,13 +98,17 @@ const Plant = ({id}) => {
}
return <div key={action.action_type} className="flex items-center gap-2 my-2">
<span>
<Button className={classNames(isDone ? "bg-green-500 hover:bg-green-700" : "bg-blue-500 hover:bg-blue-700")} onClick={() => doneTask(action.id)}>Done</Button>
<Button className={classNames(isDone ? "bg-green-500 hover:bg-green-700" : "bg-blue-500 hover:bg-blue-700")}
onClick={() => doneTask(action.id)}>
Done
</Button>
</span>
<span className="capitalize font-bold">{action.action_type}</span>
{Number(action.frequency) === 0
? <span>when you want</span>
: <span> every {action.frequency} days</span>}
<span className="text-gray-500">last task {lastTask ? lastTask.toFrDate() : 'never'}</span>
{/*<span>{ archived.where('action', actionId(action.action_type)).length }</span>*/}
</div>
})}
</div>
@@ -114,7 +118,14 @@ const Plant = ({id}) => {
<ModalTitle>Add Action</ModalTitle>
<form onSubmit={handleSubmit}>
<SelectField name="action_type" className="mb-2 mt-5" value={actionForm.action_type} options={action_types} onChange={(e) => setActionForm({ ...actionForm, action_type: e.target.value })}>Name</SelectField>
<SelectField name="action_type"
className="mb-2 mt-5"
value={actionForm.action_type}
options={ACTION_TYPES}
onChange={(e) => setActionForm({ ...actionForm, action_type: e.target.value })}>
Name
</SelectField>
<InputField name="frequency"
className="mb-5"
type="number"
@@ -125,7 +136,8 @@ const Plant = ({id}) => {
</InputField>
<Button type="submit" className="block w-full mt-5 mb-2 bg-green-800 hover:bg-green-900 text-white mx-auto px-2 py-1 shadow">
<Button type="submit"
className="block w-full mt-5 mb-2 bg-green-800 hover:bg-green-900 text-white mx-auto px-2 py-1 shadow">
Add
</Button>
</form>

View File

@@ -1,9 +1,10 @@
import { useContext, useEffect, useState } from "preact/hooks";
import { PageLayout } from "../components/PageLayout";
import { UserContext } from "../Contexts";
import {PlantsContext, UserContext} from "../Contexts";
export default function Profile() {
const [user, setUser] = useContext(UserContext)
const {plants} = useContext(PlantsContext)
const [darkMode, setDarkMode] = useState(false)
useEffect(() => {
@@ -29,5 +30,8 @@ export default function Profile() {
onChange={() => handleChangeDarkMode()} />
Dark Mode
</label>
<div className="mt-5">
{plants.length} Plants
</div>
</PageLayout>
}

6
src/utilities/actions.js Normal file
View File

@@ -0,0 +1,6 @@
export const ACTION_TYPES = ['watering', 'spraying', 'bathing']
export const actionId = (action) => {
return ACTION_TYPES.findIndex(item => item === action)
}