add signup
This commit is contained in:
parent
ccc92ecea0
commit
8e744cf2dd
1
.gitignore
vendored
1
.gitignore
vendored
@ -129,4 +129,3 @@ dist
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
|
1
.npmrc
Normal file
1
.npmrc
Normal file
@ -0,0 +1 @@
|
||||
@brojs:registry=https://git.bro-js.ru/api/packages/bro-js/npm/
|
7
.prettierrc
Normal file
7
.prettierrc
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 120,
|
||||
"endOfLine": "lf",
|
||||
"semi": true
|
||||
}
|
24
bro.config.js
Normal file
24
bro.config.js
Normal file
@ -0,0 +1,24 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const pkg = require('./package');
|
||||
|
||||
module.exports = {
|
||||
apiPath: 'stubs/api',
|
||||
webpackConfig: {
|
||||
output: {
|
||||
publicPath: `/static/${pkg.name}/${process.env.VERSION || pkg.version}/`
|
||||
}
|
||||
},
|
||||
/* use https://admin.bro-js.ru/ to create config, navigations and features */
|
||||
navigations: {
|
||||
'sberhubproject.main': '/sberhubproject',
|
||||
'sberhubproject.signup': '/sberhubproject/signup',
|
||||
},
|
||||
features: {
|
||||
'sberhubproject': {
|
||||
// add your features here in the format [featureName]: { value: string }
|
||||
}
|
||||
},
|
||||
config: {
|
||||
'sberhubproject.api': '/api'
|
||||
}
|
||||
};
|
33
eslint.config.js
Normal file
33
eslint.config.js
Normal file
@ -0,0 +1,33 @@
|
||||
import globals from 'globals';
|
||||
import pluginJs from '@eslint/js';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import pluginReact from 'eslint-plugin-react';
|
||||
import pluginPrettier from 'eslint-plugin-prettier/recommended';
|
||||
import jsxA11y from 'eslint-plugin-jsx-a11y';
|
||||
import hooksPlugin from 'eslint-plugin-react-hooks';
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
{ files: ['**/*.{js,mjs,cjs,ts,jsx,tsx}'] },
|
||||
{ languageOptions: { globals: { ...globals.browser, ...globals.node } } },
|
||||
pluginJs.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
{
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect'
|
||||
}
|
||||
},
|
||||
...pluginReact.configs.flat.recommended
|
||||
},
|
||||
jsxA11y.flatConfigs.recommended,
|
||||
{
|
||||
plugins: {
|
||||
'react-hooks': hooksPlugin
|
||||
},
|
||||
rules: {
|
||||
...hooksPlugin.configs.recommended.rules
|
||||
}
|
||||
},
|
||||
pluginPrettier
|
||||
];
|
10139
package-lock.json
generated
Normal file
10139
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
38
package.json
Normal file
38
package.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "sberhubproject",
|
||||
"version": "1.0.0",
|
||||
"main": "./src/index.tsx",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "brojs server --port=8099 --with-open-browser",
|
||||
"build": "npm run clean && brojs build --dev",
|
||||
"build:prod": "npm run clean && brojs build",
|
||||
"clean": "rimraf dist",
|
||||
"eslint": "eslint ."
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"@brojs/cli": "^1.6.1",
|
||||
"@emotion/react": "^11.13.5",
|
||||
"@emotion/styled": "^11.13.5",
|
||||
"@mui/material": "^6.1.9",
|
||||
"express": "^4.19.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-router-dom": "^6.28.0",
|
||||
"react-select": "^5.8.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.14.0",
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"eslint-plugin-react": "^7.37.2",
|
||||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"globals": "^15.12.0",
|
||||
"typescript-eslint": "^8.13.0"
|
||||
}
|
||||
}
|
8
src/app.tsx
Normal file
8
src/app.tsx
Normal file
@ -0,0 +1,8 @@
|
||||
import React from 'react';
|
||||
import Main from './container/main';
|
||||
|
||||
const App = () => {
|
||||
return <Main />;
|
||||
};
|
||||
|
||||
export default App;
|
BIN
src/assets/images/student-icon.png
Normal file
BIN
src/assets/images/student-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
38
src/container/Constant.js
Normal file
38
src/container/Constant.js
Normal file
File diff suppressed because one or more lines are too long
36
src/container/hooks/useTelegram.tsx
Normal file
36
src/container/hooks/useTelegram.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
Telegram: {
|
||||
WebApp: any;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const useTelegram = () => {
|
||||
|
||||
const tg = window.Telegram.WebApp;
|
||||
const onClose = () => {
|
||||
tg.close()
|
||||
}
|
||||
|
||||
const onToggleButton = () => {
|
||||
if(tg.MainButton.isVisible) {
|
||||
tg.MainButton.hide();
|
||||
} else {
|
||||
tg.MainButton.show();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
onClose,
|
||||
onToggleButton,
|
||||
tg,
|
||||
user_id: tg.initDataUnsafe?.user?.id,
|
||||
user: tg.initDataUnsafe?.user,
|
||||
username: tg.initDataUnsafe?.user?.username,
|
||||
queryId: tg.initDataUnsafe?.query_id
|
||||
}
|
||||
}
|
||||
|
||||
export default useTelegram;
|
28
src/container/main/components/layout/header.tsx
Normal file
28
src/container/main/components/layout/header.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { getNavigationsValue } from '@brojs/cli';
|
||||
|
||||
const navigations: Array<{ name: string; href: string }> = [
|
||||
{
|
||||
name: 'Регистрация',
|
||||
href: getNavigationsValue('sberhubproject.signup')
|
||||
}
|
||||
];
|
||||
|
||||
const Header = (): React.ReactElement => {
|
||||
return (
|
||||
<header>
|
||||
<ul>
|
||||
{navigations.map((item) => {
|
||||
return (
|
||||
<li key={item.name}>
|
||||
<Link to={item.href}>{item.name}</Link>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
16
src/container/main/components/layout/index.tsx
Normal file
16
src/container/main/components/layout/index.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
import Header from './header';
|
||||
|
||||
const Layout = (): React.ReactElement => {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main>
|
||||
<Outlet />
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
9
src/container/main/index.tsx
Normal file
9
src/container/main/index.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
import { RouterProvider } from 'react-router-dom';
|
||||
import { router } from './router';
|
||||
|
||||
const Main = (): React.ReactElement => {
|
||||
return <RouterProvider router={router} />;
|
||||
};
|
||||
|
||||
export default Main;
|
18
src/container/main/router.tsx
Normal file
18
src/container/main/router.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import { createBrowserRouter } from 'react-router-dom';
|
||||
import SingUpPage from '../signup';
|
||||
import { getNavigationsValue } from '@brojs/cli';
|
||||
import Layout from './components/layout';
|
||||
|
||||
export const router = createBrowserRouter([
|
||||
{
|
||||
path: getNavigationsValue('sberhubproject.signup'),
|
||||
element: <Layout />,
|
||||
children: [
|
||||
{
|
||||
path: getNavigationsValue('sberhubproject.signup'),
|
||||
element: <SingUpPage />
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
7
src/container/signup/index.css
Normal file
7
src/container/signup/index.css
Normal file
@ -0,0 +1,7 @@
|
||||
.upload-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.basic-multi-select {
|
||||
width: 100%;
|
||||
}
|
171
src/container/signup/index.tsx
Normal file
171
src/container/signup/index.tsx
Normal file
@ -0,0 +1,171 @@
|
||||
import * as React from 'react';
|
||||
import Avatar from '@mui/material/Avatar';
|
||||
import Button from '@mui/material/Button';
|
||||
import CssBaseline from '@mui/material/CssBaseline';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import Box from '@mui/material/Box';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Container from '@mui/material/Container';
|
||||
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
||||
import axios from 'axios';
|
||||
import student_icon from '../../assets/images/student-icon.png';
|
||||
import "./index.css";
|
||||
//import useTelegram from "../hooks/useTelegram";
|
||||
import Select from 'react-select';
|
||||
import makeAnimated from 'react-select/animated';
|
||||
import { useState } from 'react';
|
||||
import { useConstant } from '../Constant';
|
||||
|
||||
const animatedComponents = makeAnimated();
|
||||
const theme = createTheme();
|
||||
|
||||
|
||||
const SingUpPage = (): React.ReactElement => {
|
||||
const [avatarUrl, setAvatarUrl] = useState<string | null>(null);
|
||||
const [selectedOption, setSelectedOption] = useState<string | null>(null);
|
||||
const handleChange = (selectedOption) => {
|
||||
setSelectedOption(selectedOption);
|
||||
};
|
||||
const { interests } = useConstant();
|
||||
//const { user_id, username, onClose } = useTelegram();
|
||||
/*
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
const data = new FormData(event.currentTarget);
|
||||
const form = {
|
||||
id: user_id,
|
||||
name: username,
|
||||
fullname: data.get('lname') + ' ' + data.get('fname'),
|
||||
about: data.get('about'), // Новое поле "Обо мне"
|
||||
photo: image,
|
||||
interests: selectedOption?.map((item) => item.value)
|
||||
};
|
||||
await axios.post("https://sergeymorykov-tg-web-backend-1a6e.twc1.net/users_reg", form);
|
||||
//await axios.post("http://localhost:5000/users_reg", form);
|
||||
delete form.photo;
|
||||
window.Telegram.WebApp.sendData(JSON.stringify(form));
|
||||
onClose();
|
||||
};
|
||||
*/
|
||||
const handleAvatarClick = () => {
|
||||
const fileInput = document.getElementById('avatar-input') as HTMLInputElement;
|
||||
fileInput.click();
|
||||
};
|
||||
|
||||
const handleAvatarChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = event.target.files[0];
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = () => {
|
||||
setAvatarUrl(reader.result as string);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
};
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<Container component="main" maxWidth="xs">
|
||||
<CssBaseline />
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: 8,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<Typography component="h1" variant="h5">
|
||||
Регистрация
|
||||
</Typography>
|
||||
<Box component="form" noValidate sx={{ mt: 3 }}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<TextField
|
||||
required
|
||||
fullWidth
|
||||
id="lname"
|
||||
label="Фамилия"
|
||||
name="lname"
|
||||
autoComplete="family-name"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<TextField
|
||||
autoComplete="given-name"
|
||||
name="fname"
|
||||
required
|
||||
fullWidth
|
||||
id="fname"
|
||||
label="Имя"
|
||||
autoFocus
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
fullWidth
|
||||
multiline
|
||||
rows={3}
|
||||
id="about"
|
||||
label="Обо мне"
|
||||
name="about"
|
||||
variant="outlined"
|
||||
placeholder="Напишите о себе"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid
|
||||
container
|
||||
spacing={0}
|
||||
direction="column"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
sx={{ paddingTop: 7, paddingLeft: 3 }}
|
||||
>
|
||||
<Avatar src={avatarUrl || student_icon} onClick={handleAvatarClick} sx={{ width: 200, height: 200 }}/>
|
||||
<input
|
||||
type="file"
|
||||
name="image"
|
||||
accept="image/*"
|
||||
onChange={handleAvatarChange}
|
||||
style={{ display: 'none' }}
|
||||
id="avatar-input"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid
|
||||
container
|
||||
spacing={0}
|
||||
direction="column"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
sx={{ paddingTop: 7, ml: 3 }}
|
||||
>
|
||||
<Select
|
||||
onChange={handleChange}
|
||||
closeMenuOnSelect={false}
|
||||
components={animatedComponents}
|
||||
isMulti
|
||||
options={interests}
|
||||
className="basic-multi-select"
|
||||
classNamePrefix="select"
|
||||
/>
|
||||
</Grid>
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
sx={{ mt: 3, mb: 2, ml: 3 }}
|
||||
>
|
||||
Регистрация
|
||||
</Button>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Box>
|
||||
</Container>
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default SingUpPage;
|
23
src/index.tsx
Normal file
23
src/index.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
|
||||
import App from './app';
|
||||
|
||||
export default () => <App />;
|
||||
|
||||
let rootElement: ReactDOM.Root;
|
||||
|
||||
export const mount = (Сomponent, element = document.getElementById('app')) => {
|
||||
const rootElement = ReactDOM.createRoot(element);
|
||||
rootElement.render(<Сomponent />);
|
||||
|
||||
if (module.hot) {
|
||||
module.hot.accept('./app', () => {
|
||||
rootElement.render(<Сomponent />);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const unmount = () => {
|
||||
rootElement.unmount();
|
||||
};
|
4
src/typings/png.d.ts
vendored
Normal file
4
src/typings/png.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
declare module '*.png' {
|
||||
const value: string;
|
||||
export default value;
|
||||
}
|
3
stubs/api/index.js
Normal file
3
stubs/api/index.js
Normal file
@ -0,0 +1,3 @@
|
||||
const router = require('express').Router();
|
||||
|
||||
module.exports = router;
|
25
tsconfig.json
Normal file
25
tsconfig.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2017"
|
||||
],
|
||||
"outDir": "./dist/",
|
||||
"sourceMap": true,
|
||||
"esModuleInterop": true,
|
||||
"noImplicitAny": false,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"target": "es6",
|
||||
"jsx": "react",
|
||||
"typeRoots": ["node_modules/@types", "src/typings"],
|
||||
"types" : ["webpack-env", "node"],
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"**/*.test.ts",
|
||||
"**/*.test.tsx",
|
||||
"node_modules/@types/jest"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user