forms
This commit is contained in:
parent
0f211115cf
commit
05b5843c08
@ -26,6 +26,6 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
config: {
|
||||
'nav2.api': '/api',
|
||||
"dry-wash.api.url": "/api"
|
||||
},
|
||||
}
|
||||
|
@ -1,39 +1,45 @@
|
||||
import globals from "globals"
|
||||
import pluginJs from "@eslint/js"
|
||||
import tseslint from "typescript-eslint"
|
||||
import pluginReact from "eslint-plugin-react"
|
||||
import globals from 'globals'
|
||||
import pluginJs from '@eslint/js'
|
||||
import tseslint from 'typescript-eslint'
|
||||
import pluginReact from 'eslint-plugin-react'
|
||||
import stylistic from '@stylistic/eslint-plugin'
|
||||
|
||||
export default [
|
||||
{ files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"] },
|
||||
{ files: ['**/*.{js,mjs,cjs,ts,jsx,tsx}'] },
|
||||
{ languageOptions: { globals: globals.browser } },
|
||||
pluginJs.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
pluginReact.configs.flat.recommended,
|
||||
{
|
||||
plugins: {
|
||||
'@stylistic': stylistic
|
||||
'@stylistic': stylistic,
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-vars": "off",
|
||||
"react/prop-types": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn", // or "error"
|
||||
rules: {
|
||||
'no-unused-vars': 'off',
|
||||
'react/prop-types': 'off',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'warn', // or "error"
|
||||
{
|
||||
"argsIgnorePattern": "^_",
|
||||
"varsIgnorePattern": "^_",
|
||||
"caughtErrorsIgnorePattern": "^_"
|
||||
}
|
||||
argsIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
caughtErrorsIgnorePattern: '^_',
|
||||
},
|
||||
],
|
||||
"sort-imports": ["error", {
|
||||
"ignoreCase": false,
|
||||
"ignoreDeclarationSort": true,
|
||||
"ignoreMemberSort": false,
|
||||
"memberSyntaxSortOrder": ["none", "all", "multiple", "single"],
|
||||
"allowSeparatedGroups": true
|
||||
}],
|
||||
semi: ["error", "never"],
|
||||
'sort-imports': [
|
||||
'error',
|
||||
{
|
||||
ignoreCase: false,
|
||||
ignoreDeclarationSort: true,
|
||||
ignoreMemberSort: false,
|
||||
memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'],
|
||||
allowSeparatedGroups: true,
|
||||
},
|
||||
],
|
||||
semi: ['error', 'never'],
|
||||
'@stylistic/indent': ['error', 2],
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
ignores: ['stubs/'],
|
||||
},
|
||||
]
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useForm, Controller } from 'react-hook-form'
|
||||
import { Box, Input } from '@chakra-ui/react'
|
||||
import { Box, Button, Input } from '@chakra-ui/react'
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
|
||||
type Inputs = {
|
||||
@ -7,7 +7,7 @@ type Inputs = {
|
||||
age: string
|
||||
}
|
||||
|
||||
export const FormTest = () => {
|
||||
export const FormTest = ({ name }) => {
|
||||
const {
|
||||
register,
|
||||
control,
|
||||
@ -16,45 +16,51 @@ export const FormTest = () => {
|
||||
reset,
|
||||
setValue,
|
||||
formState: { errors },
|
||||
} = useForm<Inputs>()
|
||||
|
||||
const [name, setName] = React.useState('')
|
||||
const [age, setAge] = React.useState('12')
|
||||
const ageRef = useRef(null)
|
||||
|
||||
useEffect(() => {
|
||||
ageRef.current.focus()
|
||||
}, [])
|
||||
} = useForm<Inputs>({
|
||||
mode: 'onChange',
|
||||
defaultValues: {
|
||||
name: name,
|
||||
age: '12',
|
||||
},
|
||||
})
|
||||
|
||||
const onSibmit = ({ name, age }) => {
|
||||
// console.log(1111111, name, age)
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
as="form"
|
||||
flexDirection="column"
|
||||
display="flex"
|
||||
onSubmit={handleSubmit(onSibmit)}
|
||||
>
|
||||
<label>
|
||||
Name:
|
||||
<Controller
|
||||
control={control}
|
||||
name="name"
|
||||
rules={{
|
||||
required: 'required 4 now',
|
||||
minLength: { value: 4, message: 'min 4 now' },
|
||||
}}
|
||||
render={({ field, fieldState, formState }) => <Input {...field} />}
|
||||
/>
|
||||
</label>
|
||||
<>
|
||||
<Box
|
||||
as="form"
|
||||
flexDirection="column"
|
||||
display="flex"
|
||||
onSubmit={handleSubmit(onSibmit)}
|
||||
>
|
||||
<label>
|
||||
Name:
|
||||
<Controller
|
||||
control={control}
|
||||
name="name"
|
||||
rules={{
|
||||
required: 'required 4 now',
|
||||
minLength: { value: 4, message: 'min 4 now' },
|
||||
}}
|
||||
render={({ field, fieldState, formState }) => <Input {...field} />}
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Age:
|
||||
<input type="number" ref={ageRef} defaultValue={age} />
|
||||
</label>
|
||||
<button type="submit">Submit</button>
|
||||
</Box>
|
||||
<label>
|
||||
Age:
|
||||
<Controller
|
||||
control={control}
|
||||
name="age"
|
||||
render={({ field, fieldState, formState }) => (
|
||||
<Input type="number" {...field} />
|
||||
)}
|
||||
/>
|
||||
</label>
|
||||
<Button type="submit">Submit</Button>
|
||||
</Box>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -41,10 +41,12 @@ export const Profile = ({
|
||||
title?: string
|
||||
}) => {
|
||||
// const [rated, setRated] = useState(user.rated || 0)
|
||||
const [editProfile, setEditProfile] = useState(false)
|
||||
|
||||
return (
|
||||
<Box mt={3} borderWidth="1px" p={3} overflowX="hidden">
|
||||
{!isLink && <FormTest />}
|
||||
{!isLink && editProfile && <FormTest name={user.name} />}
|
||||
{!editProfile && <Button onClick={() => setEditProfile(true)}>Редактировать</Button>}
|
||||
<Heading as="h2">{title || 'Данные профиля'}</Heading>
|
||||
<Box m={3}>
|
||||
<Card width={'fit-content'} shadow="2xl">
|
||||
@ -59,7 +61,7 @@ export const Profile = ({
|
||||
<CardFooter>
|
||||
{features['stars'] && (
|
||||
<Stars
|
||||
count={Number(features['stars']?.value) * 2}
|
||||
count={Number(features['stars']?.value)}
|
||||
userId={user.id}
|
||||
// rated={rated}
|
||||
// setRated={setRated}
|
||||
@ -68,15 +70,15 @@ export const Profile = ({
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Box>
|
||||
{!isLink &&
|
||||
{/* {!isLink &&
|
||||
features['buttons'] &&
|
||||
user.friends?.map((friend) => (
|
||||
user.friends?.map((friend) => ( */}
|
||||
<Counter
|
||||
key={friend.id}
|
||||
key={user.id}
|
||||
// value={rated} setValue={setRated}
|
||||
userId={friend.id}
|
||||
userId={user.id}
|
||||
/>
|
||||
))}
|
||||
{/* ))} */}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { HStack, Icon } from '@chakra-ui/react'
|
||||
import { FaRegStar, FaStar } from 'react-icons/fa6'
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import { getConfigValue } from '@brojs/cli'
|
||||
import { stars } from '../__data__/context'
|
||||
import { useUsers } from '../hooks'
|
||||
|
||||
@ -34,6 +35,19 @@ export const Stars = ({
|
||||
// setRated: starsSetRated
|
||||
// } = useStars(rated, count)
|
||||
const { rate, setUserRate } = useUsers(state => state[userId].rated)
|
||||
const handleStarsClick = (stars: number) => {
|
||||
setUserRate(userId, stars)
|
||||
fetch(getConfigValue('dry-wash.api.url') + '/user-rate', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
userId,
|
||||
stars,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<HStack>
|
||||
@ -43,7 +57,7 @@ export const Stars = ({
|
||||
key={index}
|
||||
color="orange.400"
|
||||
cursor="pointer"
|
||||
onClick={() => setUserRate(userId, index + 1)}
|
||||
onClick={() => handleStarsClick(index + 1)}
|
||||
>
|
||||
<FaRegStar />
|
||||
</Icon>
|
||||
@ -52,7 +66,7 @@ export const Stars = ({
|
||||
key={index}
|
||||
color="orange.400"
|
||||
cursor="pointer"
|
||||
onClick={() => setUserRate(userId, index + 1)}
|
||||
onClick={() => handleStarsClick(index + 1)}
|
||||
>
|
||||
<FaStar />
|
||||
</Icon>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Container, Heading } from '@chakra-ui/react'
|
||||
import React, { useState } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useParams } from 'react-router-dom'
|
||||
|
||||
import { Profile } from '../components'
|
||||
@ -47,6 +47,24 @@ const users = {
|
||||
|
||||
export const ByPage = () => {
|
||||
const params = useParams()
|
||||
const [isLoading, setIsLoading] = useState(null)
|
||||
const [data, setData] = useState(null)
|
||||
const [error, setError] = useState(null)
|
||||
|
||||
useEffect(() => {
|
||||
const getUser = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/users/' + params.userId)
|
||||
|
||||
const data = await response.json()
|
||||
} catch (e) {
|
||||
alert(e.message)
|
||||
}
|
||||
}
|
||||
|
||||
getUser()
|
||||
}, [])
|
||||
|
||||
|
||||
if (!users[params.userId]) {
|
||||
return <Heading as="h2">Пользователь не найден</Heading>
|
||||
|
@ -1,14 +1,43 @@
|
||||
import { HStack } from '@chakra-ui/react'
|
||||
import React, { memo } from 'react'
|
||||
import React, { memo, useEffect, useState } from 'react'
|
||||
|
||||
import { Profile } from '../components'
|
||||
import { users } from '../__data__/users'
|
||||
|
||||
export const Friends = memo(() => {
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [data, setData] = useState(null)
|
||||
const [error, setError] = useState(null)
|
||||
|
||||
useEffect(() => {
|
||||
const getUser = async () => {
|
||||
setIsLoading(true)
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/users/')
|
||||
|
||||
if (response.ok) {
|
||||
setData((await response.json()).body)
|
||||
} else {
|
||||
throw 'Что-то пошло не так'
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
setError(e.message)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
getUser()
|
||||
}, [])
|
||||
|
||||
if(!data || isLoading) return <h1>loading...</h1>
|
||||
|
||||
return (
|
||||
<HStack>
|
||||
<Profile user={users['some-user-id']} />
|
||||
<Profile user={users['2']} />
|
||||
<Profile user={data['some-user-id']} />
|
||||
<Profile user={data['2']} />
|
||||
</HStack>
|
||||
)
|
||||
})
|
||||
|
@ -1,8 +1,53 @@
|
||||
const router = require('express').Router();
|
||||
const router2 = require('express').Router();
|
||||
const path = require('node:path')
|
||||
const fs = require('node:fs')
|
||||
|
||||
const timer = (time = 300) => (req, res, next) => setTimeout(next, time);
|
||||
let stubs = {
|
||||
users: 'success'
|
||||
}
|
||||
|
||||
router.use(timer());
|
||||
const timer = (time) => (req, res, next) => {
|
||||
setTimeout(next, time)
|
||||
}
|
||||
|
||||
timer.slow = timer(5000)
|
||||
timer.fast = timer(300)
|
||||
|
||||
// router.use(timer.fast)
|
||||
|
||||
router.post('/user-rate', (req, res) => {
|
||||
console.log(req.body)
|
||||
res.status(500).send({ ok: false })
|
||||
})
|
||||
|
||||
router.use('/admin', router2)
|
||||
|
||||
router.get('/users',
|
||||
(req, res, next) => {
|
||||
res.status(stubs.users.includes('error') ? 400 : 200).send(require(`../json/users/${stubs.users}.json`))
|
||||
})
|
||||
|
||||
router2.get('/', (req, res) => {
|
||||
res.send(`
|
||||
<h2>Users</h2>
|
||||
<ul>
|
||||
<li><button onclick="fetch('/api/admin/users/success')" style="background-color: ${stubs.users === 'success' ? 'green' : '#ccc'}">success</button></li>
|
||||
<li><button onclick="fetch('/api/admin/users/error')" style="background-color: ${stubs.users === 'error' ? 'green' : '#ccc'}">error</button></li>
|
||||
</ul>
|
||||
|
||||
<h2>Users</h2>
|
||||
<ul>
|
||||
<li><button onclick="fetch('/api/admin/users/success')" style="background-color: ${stubs.users === 'success' ? 'green' : '#ccc'}">success</button></li>
|
||||
<li><button onclick="fetch('/api/admin/users/error')" style="background-color: ${stubs.users === 'error' ? 'green' : '#ccc'}">error</button></li>
|
||||
</ul>
|
||||
`)
|
||||
})
|
||||
|
||||
router2.get('/:stubName/:value', (req, res) => {
|
||||
const { stubName, value } = req.params
|
||||
|
||||
stubs[stubName] = value
|
||||
})
|
||||
|
||||
module.exports = router;
|
||||
|
6
stubs/json/users/empty.json
Normal file
6
stubs/json/users/empty.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"success": false,
|
||||
"body": {
|
||||
|
||||
}
|
||||
}
|
41
stubs/json/users/success.json
Normal file
41
stubs/json/users/success.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"success": false,
|
||||
"body": {
|
||||
"some-user-id": {
|
||||
"id": "some-user-id",
|
||||
"name": "alexandr",
|
||||
"surname": null,
|
||||
"email": null,
|
||||
"rated": 3,
|
||||
"avatar": "https://www.gravatar.com/avatar/6529e885535ef67a3fad810ad71167c2c03f79480936e9b3a714731753cbb47e?d=robohash",
|
||||
"friends": [
|
||||
{
|
||||
"id": "2",
|
||||
"name": "not alexandr",
|
||||
"surname": null,
|
||||
"email": null,
|
||||
"rated": 2,
|
||||
"avatar": "https://www.gravatar.com/avatar/6e?d=robohash"
|
||||
}
|
||||
]
|
||||
},
|
||||
"2": {
|
||||
"id": "2",
|
||||
"name": "not alexandr",
|
||||
"surname": null,
|
||||
"email": null,
|
||||
"rated": 2,
|
||||
"avatar": "https://www.gravatar.com/avatar/6e?d=robohash",
|
||||
"friends": [
|
||||
{
|
||||
"id": "some-user-id",
|
||||
"name": "alexandr",
|
||||
"surname": null,
|
||||
"email": null,
|
||||
"rated": 3,
|
||||
"avatar": "https://www.gravatar.com/avatar/6529e885535ef67a3fad810ad71167c2c03f79480936e9b3a714731753cbb47e?d=robohash"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user