add signup

This commit is contained in:
admin 2024-11-30 09:47:34 +03:00
parent ccc92ecea0
commit 8e744cf2dd
21 changed files with 10629 additions and 2 deletions

1
.gitignore vendored
View File

@ -129,4 +129,3 @@ dist
.yarn/build-state.yml .yarn/build-state.yml
.yarn/install-state.gz .yarn/install-state.gz
.pnp.* .pnp.*

1
.npmrc Normal file
View File

@ -0,0 +1 @@
@brojs:registry=https://git.bro-js.ru/api/packages/bro-js/npm/

7
.prettierrc Normal file
View File

@ -0,0 +1,7 @@
{
"singleQuote": true,
"trailingComma": "none",
"printWidth": 120,
"endOfLine": "lf",
"semi": true
}

24
bro.config.js Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

38
package.json Normal file
View 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
View File

@ -0,0 +1,8 @@
import React from 'react';
import Main from './container/main';
const App = () => {
return <Main />;
};
export default App;

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

38
src/container/Constant.js Normal file

File diff suppressed because one or more lines are too long

View 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;

View 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;

View 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;

View 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;

View 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 />
}
]
}
]);

View File

@ -0,0 +1,7 @@
.upload-input {
display: none;
}
.basic-multi-select {
width: 100%;
}

View 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
View 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
View File

@ -0,0 +1,4 @@
declare module '*.png' {
const value: string;
export default value;
}

3
stubs/api/index.js Normal file
View File

@ -0,0 +1,3 @@
const router = require('express').Router();
module.exports = router;

25
tsconfig.json Normal file
View 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"
]
}