Created logic for creating lists
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
ab57857deb
commit
28069a92f1
@ -1,85 +1,75 @@
|
||||
import { FC, FormEvent, SyntheticEvent, useState } from 'react'
|
||||
import { FC, FormEvent, SyntheticEvent, useEffect, useState } from 'react'
|
||||
import { result } from '../../../common/result'
|
||||
import { createWish, Wish } from '../models'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
|
||||
interface CreateWishProps {
|
||||
onFocus: () => void
|
||||
hasFocus: boolean
|
||||
onSubmit: (wish: Wish) => void
|
||||
wish: Wish
|
||||
}
|
||||
|
||||
const CreateWish: FC<CreateWishProps> = (props) => {
|
||||
const [focused, setFocused] = useState<boolean>(false)
|
||||
|
||||
const onSubmit = (e: SyntheticEvent) => {
|
||||
e.preventDefault()
|
||||
|
||||
const target = e.target as typeof e.target & {
|
||||
wishName: { value: string }
|
||||
wishDescription: { value?: string }
|
||||
wishLink: { value?: string }
|
||||
}
|
||||
|
||||
const wishRes = createWish(
|
||||
target.wishName.value,
|
||||
target.wishDescription.value,
|
||||
target.wishLink.value
|
||||
)
|
||||
|
||||
result.tap(wishRes, (wish) => {
|
||||
props.onSubmit(wish)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div onFocus={() => setFocused(true)}>
|
||||
<BasePrompt>
|
||||
<form onSubmit={onSubmit}>
|
||||
<div className="shadow p-4 space-y-6 bg-white">
|
||||
<div className="p-1 rounded space-y-6 bg-pink-100">
|
||||
<div onFocus={() => props.onFocus()}>
|
||||
<div className="space-y-6 rounded bg-pink-100 p-1">
|
||||
<div className="bg-pink-100 transition-all">
|
||||
<input
|
||||
type="text"
|
||||
name="wishName"
|
||||
placeholder="Your wish!"
|
||||
className="appearance-none w-full bg-pink-100 text-lg text-center p-6 outline-none"
|
||||
className="w-full appearance-none bg-pink-100 p-6 text-center text-lg outline-none"
|
||||
onChange={(e) =>
|
||||
props.onSubmit({ ...props.wish, name: e.target.value })
|
||||
}
|
||||
value={props.wish.name}
|
||||
/>
|
||||
<div className={focused ? 'block' : 'hidden'}>
|
||||
<InnerWishPrompt />
|
||||
<div className={props.hasFocus ? 'block' : 'hidden'}>
|
||||
<InnerWishPrompt wish={props.wish} onChange={props.onSubmit} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
className="py-2 px-4 bg-pink-400 rounded text-white"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</BasePrompt>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const InnerWishPrompt: FC = (props) => {
|
||||
interface InnerWishPromptInterface {
|
||||
wish: Wish
|
||||
onChange: (wish: Wish) => void
|
||||
}
|
||||
|
||||
const InnerWishPrompt: FC<InnerWishPromptInterface> = (props) => {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<textarea
|
||||
name="wishDescription"
|
||||
placeholder="Description"
|
||||
className="block appearance-none w-full resize-none rounded py-3 px-4 outline-none bg-pink-100"
|
||||
className="block w-full resize-none appearance-none rounded bg-pink-100 py-3 px-4 outline-none"
|
||||
onChange={(e) =>
|
||||
props.onChange({ ...props.wish, description: e.target.value })
|
||||
}
|
||||
value={props.wish.description}
|
||||
/>
|
||||
<div className="h-0.5 w-3/4 m-auto w-content bg-gray-300" />
|
||||
<div className="w-content m-auto h-0.5 w-3/4 bg-gray-300" />
|
||||
<input
|
||||
type="text"
|
||||
name="wishLink"
|
||||
placeholder="https://example.mywish"
|
||||
className="block appearance-none w-full rounded py-3 px-4 outline-none bg-pink-100"
|
||||
className="block w-full appearance-none rounded bg-pink-100 py-3 px-4 outline-none"
|
||||
onChange={(e) =>
|
||||
props.onChange({ ...props.wish, link: e.target.value })
|
||||
}
|
||||
value={props.wish.link}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const BasePrompt: FC = (props) => <div>{props.children}</div>
|
||||
export const BasePrompt: FC = (props) => (
|
||||
<div>
|
||||
<div className="space-y-6 bg-white p-4 shadow">{props.children}</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default CreateWish
|
||||
|
@ -1,18 +1,21 @@
|
||||
import { result } from '../../common/result'
|
||||
|
||||
export type Wish = {
|
||||
id: string
|
||||
name: string
|
||||
description?: string
|
||||
link?: string
|
||||
}
|
||||
|
||||
export const createWish = (
|
||||
id: string,
|
||||
name: string,
|
||||
description?: string,
|
||||
link?: string
|
||||
description: string = '',
|
||||
link: string = ''
|
||||
): result.Result<Wish, string> => {
|
||||
if (typeof name !== 'undefined' && name.length > 0) {
|
||||
if (typeof name !== 'undefined') {
|
||||
return result.ok({
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
link,
|
||||
|
@ -7,6 +7,7 @@ interface HomeLayoutProps {
|
||||
}
|
||||
const HomeLayout: FC<HomeLayoutProps> = (props) => {
|
||||
return (
|
||||
<div className="bg-pink-50 min-h-screen">
|
||||
<div className={styles.root + ' space-x-6 pt-14'}>
|
||||
<h1 className="text-2xl space-x-2">
|
||||
<span>Wishes</span>
|
||||
@ -15,6 +16,7 @@ const HomeLayout: FC<HomeLayoutProps> = (props) => {
|
||||
</h1>
|
||||
<main className="pt-20">{props.children}</main>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -7,12 +7,15 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "latest",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-uuid": "^1.0.2",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "17.0.4",
|
||||
"@types/react": "17.0.38",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"autoprefixer": "^10.4.0",
|
||||
"postcss": "^8.4.5",
|
||||
"prettier": "^2.6.2",
|
||||
|
@ -1,20 +1,90 @@
|
||||
import { NextPage } from 'next'
|
||||
import HomeLayout from '../../components/layout/home/HomeLayout'
|
||||
import CreateWish from '../../components/domain/wishes/createWish/CreateWish'
|
||||
import CreateWish, {
|
||||
BasePrompt,
|
||||
} from '../../components/domain/wishes/createWish/CreateWish'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { createWish, Wish } from '../../components/domain/wishes/models'
|
||||
import { v4 } from 'uuid'
|
||||
import { result } from '../../components/common/result'
|
||||
|
||||
interface WishItem {
|
||||
value: Wish
|
||||
dirty: boolean
|
||||
focus: boolean
|
||||
}
|
||||
|
||||
const HomePage: NextPage = (props) => {
|
||||
const stableId = useMemo(() => v4(), [])
|
||||
|
||||
const [wishes, setWishes] = useState<{ [key: string]: WishItem }>({
|
||||
[stableId]: {
|
||||
value: result.getValue(createWish(stableId, '')),
|
||||
dirty: false,
|
||||
focus: false,
|
||||
},
|
||||
})
|
||||
|
||||
const wishArr = useMemo(() => Array.from(Object.values(wishes)), [wishes])
|
||||
const allDirty = useMemo(
|
||||
() => wishArr.map((w) => w.dirty).reduce((prev, curr) => prev && curr),
|
||||
[wishArr]
|
||||
)
|
||||
useMemo(() => {
|
||||
if (!allDirty) {
|
||||
return
|
||||
}
|
||||
|
||||
const id = v4()
|
||||
setWishes((wishes) => ({
|
||||
...wishes,
|
||||
[id]: {
|
||||
value: result.getValue(createWish(id, '')),
|
||||
dirty: false,
|
||||
focus: false,
|
||||
},
|
||||
}))
|
||||
}, [allDirty])
|
||||
|
||||
const submit = (wishes: Wish[]) => {
|
||||
console.log(wishes)
|
||||
}
|
||||
|
||||
return (
|
||||
<HomeLayout page="home">
|
||||
<div>
|
||||
<BasePrompt>
|
||||
{wishArr.map((wish) => (
|
||||
<CreateWish
|
||||
onSubmit={(wish) => {
|
||||
console.log(wish)
|
||||
}}
|
||||
key={wish.value.id}
|
||||
hasFocus={wish.focus}
|
||||
onFocus={() => {
|
||||
console.log('focused')
|
||||
setWishes((wishes) => ({
|
||||
...Array.from(Object.values(wishes)) // Get array
|
||||
.map((w) => ({ ...w, focus: false })) // Reset focus for all
|
||||
.reduce((obj, cur) => ({ ...obj, [cur.value.id]: cur }), {}), // Translate to object
|
||||
[wish.value.id]: { ...wish, focus: true },
|
||||
}))
|
||||
}}
|
||||
onSubmit={(wish) => {
|
||||
setWishes((ws) => ({
|
||||
...ws,
|
||||
[wish.id]: { value: wish, dirty: true, focus: true },
|
||||
}))
|
||||
}}
|
||||
wish={wish.value}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="rounded bg-pink-400 py-2 px-4 text-white"
|
||||
onClick={() =>
|
||||
submit(wishArr.filter((w) => w.dirty).map((w) => w.value))
|
||||
}
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</BasePrompt>
|
||||
</HomeLayout>
|
||||
)
|
||||
}
|
||||
|
@ -3,25 +3,31 @@ lockfileVersion: 5.3
|
||||
specifiers:
|
||||
'@types/node': 17.0.4
|
||||
'@types/react': 17.0.38
|
||||
'@types/uuid': ^8.3.4
|
||||
autoprefixer: ^10.4.0
|
||||
next: latest
|
||||
postcss: ^8.4.5
|
||||
prettier: ^2.6.2
|
||||
prettier-plugin-tailwindcss: ^0.1.1
|
||||
react: ^17.0.2
|
||||
react-dom: ^17.0.2
|
||||
react: ^18.0.0
|
||||
react-dom: ^18.0.0
|
||||
react-uuid: ^1.0.2
|
||||
sass: ^1.50.1
|
||||
tailwindcss: ^3.0.7
|
||||
typescript: 4.5.4
|
||||
uuid: ^8.3.2
|
||||
|
||||
dependencies:
|
||||
next: 12.1.5_b87f661d11de3633273d58c9869b3544
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
next: 12.1.5_d7d27f3bc85bacccfb9132af84144489
|
||||
react: 18.0.0
|
||||
react-dom: 18.0.0_react@18.0.0
|
||||
react-uuid: 1.0.2
|
||||
uuid: 8.3.2
|
||||
|
||||
devDependencies:
|
||||
'@types/node': 17.0.4
|
||||
'@types/react': 17.0.38
|
||||
'@types/uuid': 8.3.4
|
||||
autoprefixer: 10.4.5_postcss@8.4.12
|
||||
postcss: 8.4.12
|
||||
prettier: 2.6.2
|
||||
@ -185,6 +191,10 @@ packages:
|
||||
resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
|
||||
dev: true
|
||||
|
||||
/@types/uuid/8.3.4:
|
||||
resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==}
|
||||
dev: true
|
||||
|
||||
/acorn-node/1.8.2:
|
||||
resolution: {integrity: sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==}
|
||||
dependencies:
|
||||
@ -457,7 +467,7 @@ packages:
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
/next/12.1.5_b87f661d11de3633273d58c9869b3544:
|
||||
/next/12.1.5_d7d27f3bc85bacccfb9132af84144489:
|
||||
resolution: {integrity: sha512-YGHDpyfgCfnT5GZObsKepmRnne7Kzp7nGrac07dikhutWQug7hHg85/+sPJ4ZW5Q2pDkb+n0FnmLkmd44htIJQ==}
|
||||
engines: {node: '>=12.22.0'}
|
||||
hasBin: true
|
||||
@ -478,10 +488,10 @@ packages:
|
||||
'@next/env': 12.1.5
|
||||
caniuse-lite: 1.0.30001332
|
||||
postcss: 8.4.5
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
react: 18.0.0
|
||||
react-dom: 18.0.0_react@18.0.0
|
||||
sass: 1.50.1
|
||||
styled-jsx: 5.0.1_react@17.0.2
|
||||
styled-jsx: 5.0.1_react@18.0.0
|
||||
optionalDependencies:
|
||||
'@next/swc-android-arm-eabi': 12.1.5
|
||||
'@next/swc-android-arm64': 12.1.5
|
||||
@ -514,11 +524,6 @@ packages:
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/object-assign/4.1.1:
|
||||
resolution: {integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/object-hash/3.0.0:
|
||||
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
|
||||
engines: {node: '>= 6'}
|
||||
@ -627,23 +632,25 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/react-dom/17.0.2_react@17.0.2:
|
||||
resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==}
|
||||
/react-dom/18.0.0_react@18.0.0:
|
||||
resolution: {integrity: sha512-XqX7uzmFo0pUceWFCt7Gff6IyIMzFUn7QMZrbrQfGxtaxXZIcGQzoNpRLE3fQLnS4XzLLPMZX2T9TRcSrasicw==}
|
||||
peerDependencies:
|
||||
react: 17.0.2
|
||||
react: ^18.0.0
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
object-assign: 4.1.1
|
||||
react: 17.0.2
|
||||
scheduler: 0.20.2
|
||||
react: 18.0.0
|
||||
scheduler: 0.21.0
|
||||
dev: false
|
||||
|
||||
/react/17.0.2:
|
||||
resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==}
|
||||
/react-uuid/1.0.2:
|
||||
resolution: {integrity: sha512-5e0GM16uuQj9MdRJlZ0GdLC8LKMwpU9PIqYmF27s3fIV2z+rLyASTaiW4aKzSY4DyGanz+ImzsECkftwGWfAwA==}
|
||||
dev: false
|
||||
|
||||
/react/18.0.0:
|
||||
resolution: {integrity: sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
object-assign: 4.1.1
|
||||
dev: false
|
||||
|
||||
/readdirp/3.6.0:
|
||||
@ -683,18 +690,17 @@ packages:
|
||||
source-map-js: 1.0.2
|
||||
dev: true
|
||||
|
||||
/scheduler/0.20.2:
|
||||
resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==}
|
||||
/scheduler/0.21.0:
|
||||
resolution: {integrity: sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==}
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
object-assign: 4.1.1
|
||||
dev: false
|
||||
|
||||
/source-map-js/1.0.2:
|
||||
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
/styled-jsx/5.0.1_react@17.0.2:
|
||||
/styled-jsx/5.0.1_react@18.0.0:
|
||||
resolution: {integrity: sha512-+PIZ/6Uk40mphiQJJI1202b+/dYeTVd9ZnMPR80pgiWbjIwvN2zIp4r9et0BgqBuShh48I0gttPlAXA7WVvBxw==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
peerDependencies:
|
||||
@ -707,7 +713,7 @@ packages:
|
||||
babel-plugin-macros:
|
||||
optional: true
|
||||
dependencies:
|
||||
react: 17.0.2
|
||||
react: 18.0.0
|
||||
dev: false
|
||||
|
||||
/supports-preserve-symlinks-flag/1.0.0:
|
||||
@ -762,6 +768,11 @@ packages:
|
||||
resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=}
|
||||
dev: true
|
||||
|
||||
/uuid/8.3.2:
|
||||
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/xtend/4.0.2:
|
||||
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
|
||||
engines: {node: '>=0.4'}
|
||||
|
@ -13,7 +13,8 @@
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true
|
||||
"incremental": true,
|
||||
"downlevelIteration":true
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
|
Loading…
Reference in New Issue
Block a user