fix add plant
This commit is contained in:
28
.eslintrc.json
Normal file
28
.eslintrc.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"jest/globals": true
|
||||||
|
},
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaFeatures": {
|
||||||
|
"jsx": true
|
||||||
|
},
|
||||||
|
"ecmaVersion": 12,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"jest"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"jest/no-disabled-tests": "warn",
|
||||||
|
"jest/no-focused-tests": "error",
|
||||||
|
"jest/no-identical-title": "error",
|
||||||
|
"jest/prefer-to-have-length": "warn",
|
||||||
|
"jest/valid-expect": "error",
|
||||||
|
"no-restricted-syntax": ["warn", {
|
||||||
|
"selector": "CallExpression[callee.object.name='console'][callee.property.name!=/^(warn|info)$/]",
|
||||||
|
"message": "Unexpected property on console object was called"
|
||||||
|
}],
|
||||||
|
"semi": [2, "never"]
|
||||||
|
}
|
||||||
|
}
|
||||||
10375
package-lock.json
generated
10375
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
27
package.json
27
package.json
@@ -6,19 +6,38 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "preact build",
|
"build": "preact build",
|
||||||
"serve": "sirv build --port 8080 --cors --single",
|
"serve": "sirv build --port 8080 --cors --single",
|
||||||
"dev": "preact watch"
|
"dev": "preact watch",
|
||||||
|
"lint": "eslint src",
|
||||||
|
"test": "jest"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"extends": "preact",
|
||||||
|
"ignorePatterns": [
|
||||||
|
"build/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"enzyme": "^3.10.0",
|
"enzyme": "^3.10.0",
|
||||||
"enzyme-adapter-preact-pure": "^2.0.0",
|
"enzyme-adapter-preact-pure": "^2.0.0",
|
||||||
|
"eslint": "^6.0.1",
|
||||||
|
"eslint-config-preact": "^1.1.0",
|
||||||
|
"eslint-plugin-jest": "^25.7.0",
|
||||||
|
"jest": "^24.9.0",
|
||||||
|
"jest-preset-preact": "^1.0.0",
|
||||||
"preact-cli": "^3.0.0",
|
"preact-cli": "^3.0.0",
|
||||||
"preact-cli-tailwind": "^3.0.0",
|
|
||||||
"sirv-cli": "1.0.3"
|
"sirv-cli": "1.0.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"preact": "^10.3.2",
|
"preact": "^10.3.2",
|
||||||
|
"preact-cli-tailwind": "^3.0.0",
|
||||||
"preact-render-to-string": "^5.1.4",
|
"preact-render-to-string": "^5.1.4",
|
||||||
"preact-router": "^3.2.1",
|
"preact-router": "^3.2.1"
|
||||||
"tailwindcss": "^2.2.19"
|
},
|
||||||
|
"jest": {
|
||||||
|
"preset": "jest-preset-preact",
|
||||||
|
"setupFiles": [
|
||||||
|
"<rootDir>/tests/__mocks__/browserMocks.js",
|
||||||
|
"<rootDir>/tests/__mocks__/setupTests.js"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,3 @@
|
|||||||
import { classNames } from "../utilities/classNames"
|
|
||||||
|
|
||||||
export const Modal = ({children, isOpen, customClose = false, ...props}) => {
|
export const Modal = ({children, isOpen, customClose = false, ...props}) => {
|
||||||
|
|
||||||
@@ -26,3 +25,5 @@ export const Modal = ({children, isOpen, customClose = false, ...props}) => {
|
|||||||
export const ModalTitle = ({children, ...props}) => {
|
export const ModalTitle = ({children, ...props}) => {
|
||||||
return <div className="bg-green-700 text-white text-2xl font-bold text-center -mx-2 -mt-2 p-2 rounded-tl rounded-tr" {...props}>{children}</div>
|
return <div className="bg-green-700 text-white text-2xl font-bold text-center -mx-2 -mt-2 p-2 rounded-tl rounded-tr" {...props}>{children}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const isCloseModal = e => e.target.classList.contains("overlay") || e.target.classList.contains("close-button")
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
import { Link } from "preact-router/match"
|
import { Link } from "preact-router/match"
|
||||||
import {getPicture} from "../utilities/pictures";
|
import {getPicture} from "../utilities/pictures"
|
||||||
|
import {InputField, TextAreaField} from "./Form"
|
||||||
|
import {Button} from "./Button"
|
||||||
|
import {useState} from "preact/hooks"
|
||||||
|
|
||||||
export const PlantThumb = ({ plant, children }) => {
|
export const PlantThumb = ({ plant, children }) => {
|
||||||
|
|
||||||
return <Link href={`/plant/${plant.id}`} class="block h-48">
|
return <Link href={`/plant/${plant.id}`} class="block h-48">
|
||||||
<div className="bg-green-400 relative rounded shadow-lg flex flex-col">
|
<div className="bg-green-400 relative rounded shadow-lg flex flex-col">
|
||||||
<img src={getPicture(plant.id)} alt="" className="object-cover h-48 w-full rounded" />
|
<img src={getPicture(plant.id)} alt="" className="object-cover h-48 w-full min-h-48 min-w-48 rounded" />
|
||||||
<div className="bg-green-700 text-white p-2 text-center absolute bottom-0 w-full rounded-bl rounded-br">
|
<div className="bg-green-700 text-white p-2 text-center absolute bottom-0 w-full rounded-bl rounded-br">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
@@ -15,3 +18,18 @@ export const PlantThumb = ({ plant, children }) => {
|
|||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const PlantForm = ({children, plant, ...props}) => {
|
||||||
|
|
||||||
|
const [plantForm, setPlantForm] = useState(plant)
|
||||||
|
|
||||||
|
return <form onSubmit={e => props.onChange(e, plantForm)}>
|
||||||
|
|
||||||
|
<InputField name="name" className="mb-2 mt-5" value={plantForm.name} onChange={(e) => setPlantForm({ ...plantForm, name: e.target.value }) }>Name</InputField>
|
||||||
|
<TextAreaField name="description" className="mb-5" value={plantForm.description} onChange={(e) => setPlantForm({ ...plantForm, description: e.target.value })}>Description</TextAreaField>
|
||||||
|
|
||||||
|
<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">
|
||||||
|
{ children }
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
23
src/icon.svg
23
src/icon.svg
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.7 KiB |
@@ -1,19 +1,17 @@
|
|||||||
import { createPortal } from "preact/compat"
|
import { createPortal } from "preact/compat"
|
||||||
import { useContext, useState } from "preact/hooks"
|
import { useContext, useState } from "preact/hooks"
|
||||||
import { Button } from "../components/Button"
|
import {isCloseModal, Modal, ModalTitle} from "../components/Modals"
|
||||||
import {Modal, ModalTitle} from "../components/Modals"
|
|
||||||
import { PageLayout } from "../components/PageLayout"
|
import { PageLayout } from "../components/PageLayout"
|
||||||
import { PlantThumb } from "../components/Plants"
|
import {PlantForm, PlantThumb} from "../components/Plants"
|
||||||
import { PlantsContext } from "../Contexts"
|
import { PlantsContext } from "../Contexts"
|
||||||
import {InputField, TextAreaField} from "../components/Form"
|
|
||||||
import {Tasks} from "../components/Tasks"
|
import {Tasks} from "../components/Tasks"
|
||||||
|
|
||||||
export const Home = () => {
|
export const Home = () => {
|
||||||
const [addModal, setAddModal] = useState(false)
|
const [addModal, setAddModal] = useState(false)
|
||||||
const [plantForm, setPlantForm] = useState({})
|
|
||||||
const { plants, addPlant } = useContext(PlantsContext)
|
const { plants, addPlant } = useContext(PlantsContext)
|
||||||
|
|
||||||
const handleSubmit = (e) => {
|
const handleSubmit = (e, plantForm) => {
|
||||||
|
console.log(e)
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
addPlant(plantForm)
|
addPlant(plantForm)
|
||||||
@@ -21,8 +19,7 @@ export const Home = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleCloseAddModal = (e) => {
|
const handleCloseAddModal = (e) => {
|
||||||
if (e.target.classList.contains("overlay") ||
|
if (isCloseModal(e)) {
|
||||||
e.target.classList.contains("close-button")) {
|
|
||||||
setAddModal(false)
|
setAddModal(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,15 +47,7 @@ export const Home = () => {
|
|||||||
<ModalTitle>
|
<ModalTitle>
|
||||||
Add Plant
|
Add Plant
|
||||||
</ModalTitle>
|
</ModalTitle>
|
||||||
<form onSubmit={handleSubmit}>
|
<PlantForm plant={{}} onChange={handleSubmit}>Add</PlantForm>
|
||||||
|
|
||||||
<InputField name="name" className="mb-2 mt-5" onChange={(e) => setPlantForm({ ...plantForm, name: e.target.value }) }>Name</InputField>
|
|
||||||
<TextAreaField name="description" className="mb-5" onChange={(e) => setPlantForm({ ...plantForm, description: e.target.value })}>Description</TextAreaField>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
</Modal>,
|
</Modal>,
|
||||||
document.getElementById('app')
|
document.getElementById('app')
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
import {createPortal, useRef} from "preact/compat"
|
import {createPortal, useRef} from "preact/compat"
|
||||||
import { useContext, useEffect, useState } from "preact/hooks"
|
import { useContext, useEffect, useState } from "preact/hooks"
|
||||||
import {Button, SmallButton} from "../components/Button"
|
import {Button, SmallButton} from "../components/Button"
|
||||||
import {Modal, ModalTitle} from "../components/Modals"
|
import {isCloseModal, Modal, ModalTitle} from "../components/Modals"
|
||||||
import { PageLayout } from "../components/PageLayout"
|
import { PageLayout } from "../components/PageLayout"
|
||||||
import { PlantsContext } from "../Contexts"
|
import { PlantsContext } from "../Contexts"
|
||||||
import {InputField, SelectField, TextAreaField} from "../components/Form"
|
import {InputField, SelectField} from "../components/Form"
|
||||||
import {getPicture, storePicture} from "../utilities/pictures"
|
import {getPicture, storePicture} from "../utilities/pictures"
|
||||||
import {EditSVG, PlusSVG} from "../components/SVG";
|
import {EditSVG, PlusSVG} from "../components/SVG"
|
||||||
import {classNames} from "../utilities/classNames";
|
import {classNames} from "../utilities/classNames"
|
||||||
|
import {PlantForm} from "../components/Plants"
|
||||||
|
|
||||||
const Plant = ({id}) => {
|
const Plant = ({id}) => {
|
||||||
|
|
||||||
const [addModal, setAddModal] = useState(false)
|
const [addModal, setAddModal] = useState(false)
|
||||||
const [editModal, setEditModal] = useState(false)
|
const [editModal, setEditModal] = useState(false)
|
||||||
const [plantForm, setPlantForm] = useState({})
|
const [deleteModal, setDeleteModal] = useState(false)
|
||||||
const {plants, editPlant, removePlant, addAction, doneTask, history} = useContext(PlantsContext)
|
const {plants, editPlant, removePlant, addAction, doneTask, history} = useContext(PlantsContext)
|
||||||
const [plant, setPlant] = useState({})
|
const [plant, setPlant] = useState({})
|
||||||
const [actionForm, setActionForm] = useState({})
|
const [actionForm, setActionForm] = useState({})
|
||||||
@@ -42,7 +43,7 @@ const Plant = ({id}) => {
|
|||||||
setAddModal(false)
|
setAddModal(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleEditSubmit = (e) => {
|
const handleEditSubmit = (e, plantForm) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
editPlant(plantForm)
|
editPlant(plantForm)
|
||||||
@@ -50,39 +51,41 @@ const Plant = ({id}) => {
|
|||||||
setPlant(plantForm)
|
setPlant(plantForm)
|
||||||
}
|
}
|
||||||
|
|
||||||
const isCloseModal = e => e.target.classList.contains("overlay") || e.target.classList.contains("close-button")
|
|
||||||
|
|
||||||
const handleCloseAddModal = (e) => {
|
const handleCloseAddModal = (e) => {
|
||||||
if (isCloseModal(e)) {
|
if (isCloseModal(e)) {
|
||||||
setAddModal(false)
|
setAddModal(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleOpenEditModal = () => {
|
|
||||||
setEditModal(true)
|
|
||||||
console.log(plant)
|
|
||||||
setPlantForm(plant)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleCloseEditModal = (e) => {
|
const handleCloseEditModal = (e) => {
|
||||||
if (isCloseModal(e)) {
|
if (isCloseModal(e)) {
|
||||||
setEditModal(false)
|
setEditModal(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleCloseDeleteModal = (e) => {
|
||||||
|
if (isCloseModal(e)) {
|
||||||
|
setDeleteModal(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDeletePlant = () => removePlant(plant)
|
||||||
|
|
||||||
|
const handleOpenEditModal = () => setEditModal(true)
|
||||||
|
|
||||||
const addPicture = e => storePicture(e, id)
|
const addPicture = e => storePicture(e, id)
|
||||||
|
|
||||||
return <PageLayout>
|
return <PageLayout>
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<h1 className="my-2 flex-1 text-center">{ plant.name }</h1>
|
<h1 className="my-2 flex-1 text-center">{ plant.name }</h1>
|
||||||
<div>
|
<div>
|
||||||
<Button className="bg-blue-500" onClick={() => handleOpenEditModal()}>Edit</Button>
|
<Button className="bg-blue-500 hover:bg-blue-700" onClick={() => handleOpenEditModal()}>Edit</Button>
|
||||||
{/*<Button className="bg-red-500" onClick={() => removePlant(plant)}>Delete</Button>*/}
|
<Button className="bg-red-500 hover:bg-red-700" onClick={() => setDeleteModal(true)}>Delete</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-around flex-wrap gap-5">
|
<div className="flex justify-around flex-wrap gap-5">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<img id="picture" ref={picture} src={getPicture(id)} alt=""/>
|
<img id="picture" ref={picture} src={getPicture(id)} alt="" className="inline-block min-w-[300px] min-h-[200px] bg-gray-400"/>
|
||||||
<SmallButton className="absolute top-2 left-2 cursor-pointer bg-blue-500 hover:bg-blue-700 max-w-[300px]">
|
<SmallButton className="absolute top-2 left-2 cursor-pointer bg-blue-500 hover:bg-blue-700 max-w-[300px]">
|
||||||
<label className="relative">
|
<label className="relative">
|
||||||
<EditSVG className="w-4 h-4 block z-10 cursor-pointer" />
|
<EditSVG className="w-4 h-4 block z-10 cursor-pointer" />
|
||||||
@@ -90,7 +93,9 @@ const Plant = ({id}) => {
|
|||||||
</label>
|
</label>
|
||||||
</SmallButton>
|
</SmallButton>
|
||||||
</div>
|
</div>
|
||||||
<p className="flex-1">{ plant.description }</p>
|
<div className="flex-1">
|
||||||
|
<p>{ plant.description }</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
@@ -138,15 +143,17 @@ const Plant = ({id}) => {
|
|||||||
<ModalTitle>
|
<ModalTitle>
|
||||||
Edit Plant
|
Edit Plant
|
||||||
</ModalTitle>
|
</ModalTitle>
|
||||||
<form onSubmit={handleEditSubmit}>
|
<PlantForm plant={plant} onChange={handleEditSubmit}>Add</PlantForm>
|
||||||
|
</Modal>,
|
||||||
|
app
|
||||||
|
)}
|
||||||
|
|
||||||
<InputField name="name" className="mb-2 mt-5" value={plantForm.name} onChange={(e) => setPlantForm({ ...plantForm, name: e.target.value }) }>Name</InputField>
|
{createPortal(
|
||||||
<TextAreaField name="description" className="mb-5" value={plantForm.description} onChange={(e) => setPlantForm({ ...plantForm, description: e.target.value })}>Description</TextAreaField>
|
<Modal isOpen={deleteModal} onChange={handleCloseDeleteModal}>
|
||||||
|
<ModalTitle>
|
||||||
<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">
|
Delete Plant ?
|
||||||
Edit
|
</ModalTitle>
|
||||||
</Button>
|
<Button className="bg-red-500 hover:bg-red-700 mt-10" onClick={handleDeletePlant}>Confirm delete plant</Button>
|
||||||
</form>
|
|
||||||
</Modal>,
|
</Modal>,
|
||||||
app
|
app
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
import { setupRouting } from 'preact-cli/sw'
|
import { getFiles, setupPrecaching, setupRouting } from 'preact-cli/sw/'
|
||||||
|
|
||||||
setupRouting()
|
setupRouting()
|
||||||
|
setupPrecaching(getFiles())
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const pictureName = id => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const getPicture = id => {
|
export const getPicture = id => {
|
||||||
return localStorage.getItem('picture-' + id ?? '')
|
return localStorage.getItem('picture-' + id ?? '') ?? ""
|
||||||
}
|
}
|
||||||
|
|
||||||
export const storePicture = (e, id) => {
|
export const storePicture = (e, id) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user