diff --git a/packages/client/src/assets/RU.svg b/packages/client/src/assets/RU.svg new file mode 100644 index 0000000..efd6300 --- /dev/null +++ b/packages/client/src/assets/RU.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/client/src/assets/ya-btn.png b/packages/client/src/assets/ya-btn.png new file mode 100644 index 0000000..b23370d Binary files /dev/null and b/packages/client/src/assets/ya-btn.png differ diff --git a/packages/client/src/components/YandexIcon/YandexIcon.tsx b/packages/client/src/components/YandexIcon/YandexIcon.tsx new file mode 100644 index 0000000..dc33183 --- /dev/null +++ b/packages/client/src/components/YandexIcon/YandexIcon.tsx @@ -0,0 +1,5 @@ +import icon from '@assets/RU.svg' +export const YandexIcon = () => { + return + +} \ No newline at end of file diff --git a/packages/client/src/entry-client.tsx b/packages/client/src/entry-client.tsx index 0e7b0b5..574f034 100644 --- a/packages/client/src/entry-client.tsx +++ b/packages/client/src/entry-client.tsx @@ -14,21 +14,21 @@ declare global { } } -// window.addEventListener('load', () => { -// if ('serviceWorker' in navigator) { -// navigator.serviceWorker -// .register('/sw.js') -// .then(registration => { -// console.log( -// 'ServiceWorker registration successful with scope: ', -// registration.scope -// ) -// }) -// .catch((error: string) => { -// console.log('ServiceWorker registration failed: ', error) -// }) -// } -// }) +window.addEventListener('load', () => { + if ('serviceWorker' in navigator) { + navigator.serviceWorker + .register('/sw.js') + .then(registration => { + console.log( + 'ServiceWorker registration successful with scope: ', + registration.scope + ) + }) + .catch((error: string) => { + console.log('ServiceWorker registration failed: ', error) + }) + } +}) ReactDOM.hydrateRoot( document.getElementById('root') as HTMLElement, diff --git a/packages/client/src/hooks/useAuth.ts b/packages/client/src/hooks/useAuth.ts index 8d0ab63..0289463 100644 --- a/packages/client/src/hooks/useAuth.ts +++ b/packages/client/src/hooks/useAuth.ts @@ -11,9 +11,9 @@ export const useAuth = () => { user.id ? navigate('/game/start') : dispatch(fetchUser()).then(res => { - if (res.type === 'auth/fetch/rejected') { - return navigate('/auth') - } - }) + if (res.type === 'auth/fetch/rejected') { + return navigate('/auth') + } + }) } } diff --git a/packages/client/src/hooks/useOAuth.ts b/packages/client/src/hooks/useOAuth.ts new file mode 100644 index 0000000..4ee93e4 --- /dev/null +++ b/packages/client/src/hooks/useOAuth.ts @@ -0,0 +1,23 @@ +import { oauthYandex, fetchUser } from '@store/actions/AuthActionCreators' +import { useAppDispatch } from '@store/index' +import { OauthData } from '@store/types' + +export const useOAuth = () => { + const REDIRECT_URI = 'http://localhost:3000' + const dispatch = useAppDispatch() + const url = document.location.href + const code = url.split('=').pop(); + return () => { + if (/code/.test(url)) { + dispatch(oauthYandex({ + code: code, + redirect_uri: REDIRECT_URI + } as OauthData)) + .then(res => { + if (res.payload === 'OK') { + dispatch(fetchUser()) + } + }) + } + } +} diff --git a/packages/client/src/hooks/useRegister.ts b/packages/client/src/hooks/useRegister.ts index f112654..87ace58 100644 --- a/packages/client/src/hooks/useRegister.ts +++ b/packages/client/src/hooks/useRegister.ts @@ -1,4 +1,4 @@ -import { register } from '../store/actions/AuthActionCreators' +import { register } from '../store/actions/AuthActionCreators' import { useAppDispatch } from '../store/index' import { UserData } from '../store/types' import { useNavigate } from 'react-router-dom' diff --git a/packages/client/src/hooks/useServiceId.tsx b/packages/client/src/hooks/useServiceId.tsx new file mode 100644 index 0000000..c6fdb00 --- /dev/null +++ b/packages/client/src/hooks/useServiceId.tsx @@ -0,0 +1,17 @@ +import { getServiceId } from "@store/actions/AuthActionCreators" +import { useAppDispatch } from "@store/index" + +export const useServiceId = () => { + const dispatch = useAppDispatch() + const REDIRECT_URI = 'http://localhost:3000'; + // const REDIRECT_URI =`http://localhost:${__CLIENT_PORT__}` + + return () => { + dispatch(getServiceId()) + .then(res => { + if (res.payload.service_id) { + document.location = `https://oauth.yandex.ru/authorize?response_type=code&client_id=${res.payload.service_id}&redirect_uri=${REDIRECT_URI}` + } + }) + } +} \ No newline at end of file diff --git a/packages/client/src/pages/LoginPage/Login.tsx b/packages/client/src/pages/LoginPage/Login.tsx index 2bad7ca..3d912a2 100644 --- a/packages/client/src/pages/LoginPage/Login.tsx +++ b/packages/client/src/pages/LoginPage/Login.tsx @@ -13,19 +13,35 @@ import { useLogin } from '../../hooks/useLogin' import { useUser } from '../../hooks/useUser' import { fetchUser } from '../../store/actions/UserActionCreators' import { useAppDispatch } from '../../store/index' +import { styled } from '@mui/material/styles' +import { useServiceId } from '../../hooks/useServiceId' export default function Login() { const user = useUser() const dispatch = useAppDispatch() const navigate = useNavigate() const login = useLogin() + const location = useServiceId() + + const YandexIdButton = styled(Button)({ + color: ' white', + width: '100%', + height: '44px', + backgroundColor: 'black', + textTransform: 'none', + '&:hover': { + backgroundColor: 'black', + borderColor: '#0062cc', + boxShadow: 'none', + }, + }) useEffect(() => { - dispatch(fetchUser()) if (user.id) { navigate('/game/start') } - }, [navigate, user]) + dispatch(fetchUser()) + }, [user.id]) const handleLogin = (event: React.FormEvent) => { event.preventDefault() @@ -36,6 +52,7 @@ export default function Login() { } as LoginData login(authData) } + return ( @@ -83,6 +100,13 @@ export default function Login() { {' '} Войти + + или + + location()} + // startIcon={} + >Войти c Яндекс ID Еще не зарегистрированы? { + const dispatch = useAppDispatch() + const user = useAppSelector(selectUserData) + const ratingData = selectRatingData() + const [sunkenShipsPlayer, setSunkenShipsPlayer] = useState([]) //затонувшие корабли player const [sunkenShipsComp, setSunkenShipsComp] = useState([]) //затонувшие корабли comp @@ -54,6 +77,56 @@ const Board = ({ const [countPlayerShips, setCountPlayerShips] = useState(allPlayerShips) //Количество кораблей для уничтожения const [countCompShips, setCountCompShips] = useState(allCompShips) //Количество кораблей для уничтожения + const [playerIsWin, setPlayerIsWin] = useState(false) + + useEffect(() => { + dispatch(fetchLeaderboard()) + }, []) + + useEffect(() => { + startTime = Date.now(); //время на старте игры + }, []); + + + useEffect(() => { + //для изме-я шага по времени для игрока + if (timeHandlePlayer === undefined || timeDraw === undefined) return; + if (name === "computer") return; + + pausePlayer = getStepTimeGame(Date.now() - startTime); + pauseWorkFunPlayer = getStepTimeWorkFun(timeHandlePlayer, timeDraw); + + startTime = startTimeGame; //для нового отсчета с функции клика компа в конце + }, [timeHandlePlayer, name, timeDraw]); + + useEffect(() => { + //для изме-я шага по времени для компа + if (timeHandleComp === undefined || timeDraw === undefined) return; + if (name === "player") return; + + pauseComp = getStepTimeGame(timeClickComp); + pauseWorkFunСomp = getStepTimeWorkFun(timeHandleComp, timeDraw); + }, [timeHandleComp, name, timeDraw]); + + useEffect(() => { + if (playerIsWin && user) { + const currentUser = ratingData.find(({ data: { id } }) => id === user.id) + const score = (currentUser && currentUser.data.score + 1) ?? 1 + + const { avatar, id, display_name } = user + dispatch( + sendDataToLeaderboard({ + avatar, + id, + name: display_name ?? 'anonymous', + score, + }) + ) + + setPlayerIsWin(false) + } + }, [playerIsWin, user, ratingData]) + const canvasRef: RefObject = useRef(null) @@ -70,6 +143,8 @@ const Board = ({ if (countCompShips === 0 || countPlayerShips === 0) return if (currentPlayer === name) return //если текущий ход равен глобальному currentPlayer(тек. ход), то ничего не делаем + const firstNow = performance.now(); + if (currentPlayer === 'computer') { const cell = generateRandomCompShot() as CellArgs //рандомная ячейка компа @@ -92,6 +167,12 @@ const Board = ({ currentPlayer = 'player' //т к ход мимо переход стрельбы } } + + const secondNow = performance.now(); + timeHandleComp = secondNow - firstNow; //время работы функции клика компа + + startTimeGame = Date.now(); //начало нового отсчета + }, [ countPlayerShips, countCompShips, @@ -106,13 +187,30 @@ const Board = ({ const drawGrid = (context: CanvasRenderingContext2D) => { //отрисовка сетки, краблей, клеток попадания, клеток мимо + + const firstNow = performance.now(); + context.clearRect(0, 0, size, size) drawCells({ context, cellSize, dimMatr }) - drawNameBoard(context, nameBoard) //отрисовка названия доски + drawNameBoard( + context, + nameBoard, + name, + pausePlayer, + pauseComp, + pauseWorkFunPlayer, + pauseWorkFunСomp + ); //отрисовка названия доски с добавлением временных шагов drawLatterCoords(context, coords.letterCoords) //отрисовка координат букв доски drawNumberCoords(context, coords.numberCoords) //отрисовка координат чисел доски - drawWhoWin(context, name, countCompShips, countPlayerShips) //who win + drawWhoWin( + context, + name, + setPlayerIsWin, + countCompShips, + countPlayerShips + ) //who win drawStatusShips(context, name, countCompShips, countPlayerShips) // кол-о к уничтож клеток drawShips(context, cellSize, playerShips!) //отрисовка караблей @@ -123,6 +221,9 @@ const Board = ({ drawPastCells(context, cellSize, pastCellsPlayer) //отрис клетки мимо игрока drawPastCells(context, cellSize, pastCellsComp) //отрис клетки мимо компа + + const secondNow = performance.now(); + timeDraw = secondNow - firstNow; //время работы функции draw } if (canvasRef.current) localRef = canvasRef.current @@ -171,6 +272,8 @@ const Board = ({ if (countCompShips === 0 || countPlayerShips === 0) return if (currentPlayer === name) return //если текущий ход равен глобальному currentPlayer(тек. ход), то ничего не делаем + const firstNow = performance.now(); + if (currentPlayer === 'player') { const { offsetX, offsetY } = event.nativeEvent //определяется ячейка по которой кликнул игрок @@ -190,6 +293,9 @@ const Board = ({ currentPlayer = 'computer' // т к ход мимо переход стрельбы к компу } } + + const secondNow = performance.now(); + timeHandlePlayer = secondNow - firstNow; //время работы функции клика игрока } useEffect( diff --git a/packages/client/src/pages/game/GamePlay/helper.ts b/packages/client/src/pages/game/GamePlay/helper.ts index 87250e8..d38ff85 100644 --- a/packages/client/src/pages/game/GamePlay/helper.ts +++ b/packages/client/src/pages/game/GamePlay/helper.ts @@ -1,3 +1,4 @@ +import React from 'react' import { ShipsSet, CellArgs, @@ -6,6 +7,7 @@ import { GeneratedCoords, CellIsEngagedArgs, CellIsWithinArgs, + Winner, } from './types' export enum DirectionsOfGeneration { @@ -22,6 +24,19 @@ export const scaleBoard = 1 //масшатаб игрового поля export const canvasWidth = size + 70 //ширина всего канваса export const canvasHeight = size + 100 //высота всего канваса +//время неспешного решения о возможном клике +export const getStepTimeGame = (x: number): string => { + const y = (x / 1000).toFixed(2); + return y; +}; + +//время отработки функций +export const getStepTimeWorkFun = (tHandle: number, tDraw: number): string => { + const y = ((tHandle + tDraw) / 1000).toFixed(4); + + return y; +}; + export const shipsSet: ShipsSet[] = [ //размеры кораблей и их количество на доске // последовательность строго c size =3 и на уменьшение!!!! @@ -47,7 +62,12 @@ const drawCell = ({ context, cellSize, x, y }: DrawCellArgs): void => { //рисовать имя доски export const drawNameBoard = ( context: CanvasRenderingContext2D, - font: string + font: string, + name: string, + pausePlayer?: string, + pauseComp?: string, + pauseWorkFunPlayer?: string, + pauseWorkFunСomp?: string ): void => { context.beginPath() context.clearRect(0, 340, 300, 60) @@ -125,23 +145,27 @@ export const drawStatusShips = ( export const drawWhoWin = ( context: CanvasRenderingContext2D, name: string, + setPlayerIsWin: React.Dispatch>, countCompShips?: number, countPlayerShips?: number ): void => { const str = name === 'computer' - ? countCompShips === 0 && 'Вы победитель!!!' - : countPlayerShips === 0 && 'Компутер красавчик!!!' + ? countCompShips === 0 && Winner.PLAYER_IS_WIN + : countPlayerShips === 0 && Winner.COMP_IS_WIN + + if (str === Winner.PLAYER_IS_WIN) setPlayerIsWin(true) + if (!str) return - context.beginPath() - context.clearRect(0, 340, 300, 60) - context.rect(0, 340, 300, 60) - context.fillStyle = 'burlywood' - context.fill() - context.fillStyle = 'rgb(158, 0, 0)' - context.font = 'italic ' + 20 + 'pt Arial' - context.fillText(`${str}`, 10, 370) - context.closePath() + context.beginPath(); + context.clearRect(0, 340, 330, 60); + context.rect(0, 340, 330, 60); + context.fillStyle = "burlywood"; + context.fill(); + context.fillStyle = "rgb(158, 0, 0)"; + context.font = "italic " + 20 + "pt Arial"; + context.fillText(`${str}`, 10, 370); + context.closePath(); } // рисовать ячейки diff --git a/packages/client/src/pages/game/GamePlay/types.ts b/packages/client/src/pages/game/GamePlay/types.ts index 45ae84e..9cccbba 100644 --- a/packages/client/src/pages/game/GamePlay/types.ts +++ b/packages/client/src/pages/game/GamePlay/types.ts @@ -49,3 +49,8 @@ export type CellIsWithinArgs = { cell: CellArgs dimMatr: number } + +export enum Winner { + PLAYER_IS_WIN = 'Вы победитель!!!', + COMP_IS_WIN = 'Компутер красавчик!!!', +} diff --git a/packages/client/src/pages/game/GameStart/MenuList/MenuList.tsx b/packages/client/src/pages/game/GameStart/MenuList/MenuList.tsx index c08ade8..e1ce16f 100644 --- a/packages/client/src/pages/game/GameStart/MenuList/MenuList.tsx +++ b/packages/client/src/pages/game/GameStart/MenuList/MenuList.tsx @@ -1,9 +1,6 @@ import React from 'react' -import { Box, Button } from '@mui/material' +import { Box } from '@mui/material' import MenuItem from '../MenuItem' -import { logout } from '../../../../store/actions/AuthActionCreators' -import { useAppDispatch } from '../../../../store' -import { useNavigate } from 'react-router-dom' import PersonIcon from '@mui/icons-material/Person' import StarOutlineIcon from '@mui/icons-material/StarOutline' import ForumIcon from '@mui/icons-material/Forum' @@ -37,8 +34,6 @@ const links = [ ] export default function MenuList() { - const dispatch = useAppDispatch() - const navigate = useNavigate() return ( { + getOAuth() dispatch(fetchUser()) }, []) - const isAuth = useAuth() - const handleClick = () => { - isAuth() - } return ( - - - - - - - Для игры требуется регистрация - + + Для игры требуется регистрация + - - + - - - - История игры - - - - Считается, что игра Морской бой берет свое начало от французской - игры L'Attaque, в которую играли во время Первой мировой войны, - хотя параллели также были проведены с игрой Э.И. офицеров перед - Первой мировой войной. Первой коммерческой версией игры была - Salvo, изданная в 1931 году в США компанией Starex. Другие версии - игры были напечатаны в 1930-х и 1940-х годах, в том числе Combat: - The Battleship Game от Strathmore Company, Broadsides: A Game of - Naval Strategy Милтона Брэдли и «Морской бой Мориса Л. Фридмана». - Компания Strategy Games выпустила версию под названием Wings, в - которой были изображены самолеты, летящие над Колизеем - Лос-Анджелеса. Все эти ранние выпуски игры состояли из - предварительно напечатанных листов бумаги. + + + + История игры + + + Считается, что игра Морской бой берет свое начало от французской + игры L'Attaque, в которую играли во время Первой мировой войны, + хотя параллели также были проведены с игрой Э.И. офицеров перед + Первой мировой войной. Первой коммерческой версией игры была + Salvo, изданная в 1931 году в США компанией Starex. Другие + версии игры были напечатаны в 1930-х и 1940-х годах, в том числе + Combat: The Battleship Game от Strathmore Company, Broadsides: A + Game of Naval Strategy Милтона Брэдли и «Морской бой Мориса Л. + Фридмана». Компания Strategy Games выпустила версию под + названием Wings, в которой были изображены самолеты, летящие над + Колизеем Лос-Анджелеса. Все эти ранние выпуски игры состояли из + предварительно напечатанных листов бумаги. + + @@ -113,33 +108,56 @@ export default function Intro() { то есть расстояние между ними должно быть не менее одной клетки. - ❗️ Переставлять свои корабли после начала игры категорически - запрещено. + Правила + + + В игре принимают участие один игрок и компьютер. Корабли игрока + располагаются рандомно. При этом корабли не должны + соприкасаться, то есть расстояние между ними должно быть не + менее одной клетки. + + + ❗️ Переставлять свои корабли после начала игры категорически + запрещено. + - - Стрельба по мишеням ведется до первого промаха, то есть если игрок - попал в корабль противника, он производит следующий выстрел, и - только после его промаха ход переходит к компьютеру. На поле и на - экране промах обозначается точкой, а попадание — красным крестом в - квадрате. Каждый выстрел имеет свои координаты. Победитель тот, - кто первым уничтожит все корабли противника. - + + Стрельба по мишеням ведется до первого промаха, то есть если + игрок попал в корабль противника, он производит следующий + выстрел, и только после его промаха ход переходит к компьютеру. + На поле и на экране промах обозначается точкой, а попадание — + красным крестом в квадрате. Каждый выстрел имеет свои + координаты. Победитель тот, кто первым уничтожит все корабли + противника. + + + + + + Проект команды Praga курса Мидл-Фронтенд Разработчик + Яндекс.Практикум 2022 + + + - - - - Проект команды Praga курса Мидл-Фронтенд Разработчик - Яндекс.Практикум 2022 - - - - + ) } diff --git a/packages/client/src/pages/profile/Profile.tsx b/packages/client/src/pages/profile/Profile.tsx index 528e3c0..c19c29f 100644 --- a/packages/client/src/pages/profile/Profile.tsx +++ b/packages/client/src/pages/profile/Profile.tsx @@ -205,8 +205,8 @@ const Profile = () => { marginTop: 1, }} onClick={() => { - dispatch(logout()) - navigate('/auth') + dispatch(logout()).then(()=>navigate('/auth')) + }}> Выйти из профиля diff --git a/packages/client/src/pages/ranking/Ranking.tsx b/packages/client/src/pages/ranking/Ranking.tsx index 0103710..34a8817 100644 --- a/packages/client/src/pages/ranking/Ranking.tsx +++ b/packages/client/src/pages/ranking/Ranking.tsx @@ -1,4 +1,5 @@ -import React, { useEffect, useState } from 'react' +import { useEffect, useMemo, useState } from 'react' +import { useNavigate } from 'react-router-dom' import { Box, TableRow, @@ -11,13 +12,18 @@ import { TablePagination, Paper, Typography, + Button, } from '@mui/material' -import avatarStub from '../../assets/avatar-stub.svg' -import { useAppDispatch } from '../../store/index' -import { fetchLeaderboard } from '../../store/actions/RatingActionCreators' -import { selectRatingData } from '../../store/slices/RatingSlice' +import ArrowBackIcon from '@mui/icons-material/ArrowBack' +import avatarStub from '@assets/avatar-stub.svg' +import { useAppDispatch } from '@store/index' +import { fetchLeaderboard } from '@store/actions/RatingActionCreators' +import { selectRatingData } from '@store/slices/RatingSlice' +import { avatarContainer, container } from './styles' export default function Ranking() { + const navigate = useNavigate() + const dispatch = useAppDispatch() const ratingData = selectRatingData() @@ -42,76 +48,83 @@ export default function Ranking() { setPage(0) } + const tableData = useMemo( + () => + [...ratingData] + .sort((a, b) => b.data.score - a.data.score) + .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage), + [ratingData, page, rowsPerPage] + ) + return ( - + + Таблица лидеров - - - - - Место - Игрок - Побед - - - - {ratingData - .sort((a, b) => a.data.score - b.data.score) - .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) - .map(({ data: { score, id, name } }, index) => ( + {ratingData.length ? ( + +
+ + + Место + Игрок + Побед + + + + {tableData.map(({ data: { score, id, name } }, index) => ( - {index + 1} - - - {name} + {index + 1} + + + {name} - {score} + {score} ))} - - - - - from + ' - ' + to + ' из ' + count - } - labelRowsPerPage={Игроков на странице} - onPageChange={handleChangePage} - onRowsPerPageChange={handleChangeRowsPerPage} - /> - - -
-
+ + + + + `${from} - ${to} из ${count}` + } + labelRowsPerPage={Игроков на странице} + onPageChange={handleChangePage} + onRowsPerPageChange={handleChangeRowsPerPage} + /> + + + + + ) : ( + Пока никого нет, будь первым! :-) + )}
) } diff --git a/packages/client/src/pages/ranking/styles.ts b/packages/client/src/pages/ranking/styles.ts new file mode 100644 index 0000000..e6f27e8 --- /dev/null +++ b/packages/client/src/pages/ranking/styles.ts @@ -0,0 +1,15 @@ +export const container = { + margin: '24px auto', + display: 'flex', + flexDirection: 'column', + gap: '24px', + alignItems: 'center', +} + +export const avatarContainer = { + display: 'grid', + gridTemplateColumns: '1fr 1fr', + gridGap: '16px', + alignItems: 'center', + justifyItems: 'center', +} diff --git a/packages/client/src/store/actions/AuthActionCreators.ts b/packages/client/src/store/actions/AuthActionCreators.ts index fd5ff9e..f5cf390 100644 --- a/packages/client/src/store/actions/AuthActionCreators.ts +++ b/packages/client/src/store/actions/AuthActionCreators.ts @@ -1,6 +1,6 @@ import { createAsyncThunk } from '@reduxjs/toolkit' -import { LoginData, UserData } from '../types' import { axiosInstance } from '../../services/BaseApi' +import { LoginData, OauthData, UserData } from '@store/types' export const register = createAsyncThunk( 'auth/register', @@ -45,3 +45,27 @@ export const logout = createAsyncThunk('auth/logout', async (_, thunkApi) => { return thunkApi.rejectWithValue('Не удалось выйти из приложения') } }) + +export const getServiceId = createAsyncThunk( + 'auth/serviceid', + async (_, thunkApi) => { + try { + const response = await axiosInstance.get('oauth/yandex/service-id') + return response.data + } catch (e) { + return thunkApi.rejectWithValue('No such redirect_uri refistered') + } + } +) + +export const oauthYandex = createAsyncThunk( + 'auth/yandex', + async (data: OauthData, thunkApi) => { + try { + const response = await axiosInstance.post('oauth/yandex', data) + return response.data + } catch (e) { + return thunkApi.rejectWithValue('Пользователь не авторизован в системе') + } + } +) diff --git a/packages/client/src/store/actions/RatingActionCreators.ts b/packages/client/src/store/actions/RatingActionCreators.ts index 911f916..b6abff3 100644 --- a/packages/client/src/store/actions/RatingActionCreators.ts +++ b/packages/client/src/store/actions/RatingActionCreators.ts @@ -3,7 +3,7 @@ import { Ranking } from '../types' import { axiosInstance } from '../../services/BaseApi' -const teamName = 'praga' +const teamName = 'praga-v2' const ratingFieldName = 'score' export const fetchLeaderboard = createAsyncThunk( diff --git a/packages/client/src/store/slices/AuthSlice.ts b/packages/client/src/store/slices/AuthSlice.ts index 5be606b..3eadbf6 100644 --- a/packages/client/src/store/slices/AuthSlice.ts +++ b/packages/client/src/store/slices/AuthSlice.ts @@ -1,11 +1,19 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' import { fetchUser } from '../actions/UserActionCreators' -import { logout, register, login } from '../actions/AuthActionCreators' +import { + register, + login, + logout, + getServiceId, + oauthYandex, +} from '@store/actions/AuthActionCreators' +import { RootState } from '../index' import { StatusLoading, RequestDataState, RequestData, UserData, + OauthData, } from '../types' export interface AuthState { @@ -28,6 +36,8 @@ const initialState: AuthState = { signIn: {} as RequestDataState, getUserInfo: {} as RequestDataState, logout: {} as RequestDataState, + getServiceId: {} as RequestDataState, + oauth: {} as RequestDataState, }, } @@ -81,7 +91,35 @@ export const authSlice = createSlice({ state.requestData.logout.errorMessage = payload state.requestData.logout.status = StatusLoading.ERROR }, + [getServiceId.fulfilled.type]: state => { + state.requestData.getServiceId.status = StatusLoading.SUCCESS + }, + [getServiceId.pending.type]: state => { + state.requestData.getServiceId.status = StatusLoading.IN_PROGRESS + }, + [getServiceId.rejected.type]: ( + state, + { payload }: PayloadAction + ) => { + state.requestData.getServiceId.errorMessage = payload + state.requestData.getServiceId.status = StatusLoading.ERROR + }, + [oauthYandex.fulfilled.type]: state => { + state.requestData.oauth.status = StatusLoading.SUCCESS + }, + [oauthYandex.pending.type]: state => { + state.requestData.oauth.status = StatusLoading.IN_PROGRESS + }, + [oauthYandex.rejected.type]: ( + state, + { payload }: PayloadAction + ) => { + state.requestData.oauth.errorMessage = payload + state.requestData.oauth.status = StatusLoading.ERROR + }, }, }) +export const selectUserData = (state: RootState) => state.auth.user + export default authSlice.reducer diff --git a/packages/client/src/store/types.ts b/packages/client/src/store/types.ts index f48d3f7..45a82f5 100644 --- a/packages/client/src/store/types.ts +++ b/packages/client/src/store/types.ts @@ -21,9 +21,9 @@ export interface RankingResponse { } export interface Ranking { - id: number + id?: number name: string - avatar: string + avatar?: string score: number } @@ -74,3 +74,8 @@ export interface PassWord { oldPassword: string newPassword: string } + +export interface OauthData { + code: string + redirect_uri: string +} \ No newline at end of file diff --git a/packages/client/sw.js b/packages/client/sw.js index bb98549..1698cc0 100644 --- a/packages/client/sw.js +++ b/packages/client/sw.js @@ -1,7 +1,6 @@ const CACHE_NAME = 'my-site-cache-v1' const URLS = [ - // '/', './src/main.tsx', ] diff --git a/packages/client/vite.config.ts.timestamp-1670430434783.mjs b/packages/client/vite.config.ts.timestamp-1670430434783.mjs new file mode 100644 index 0000000..95c4af9 --- /dev/null +++ b/packages/client/vite.config.ts.timestamp-1670430434783.mjs @@ -0,0 +1,32 @@ +// vite.config.ts +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import dotenv from "dotenv"; +import path from "path"; +var __vite_injected_original_dirname = "C:\\Users\\Michael\\Desktop\\work\\praga\\packages\\client"; +dotenv.config(); +var vite_config_default = defineConfig({ + server: { + port: Number(process.env.CLIENT_PORT) || 3e3 + }, + define: { + __SERVER_PORT__: process.env.SERVER_PORT + }, + ssr: { + target: "node", + format: "cjs" + }, + plugins: [react()], + resolve: { + alias: { + "@assets": path.resolve(__vite_injected_original_dirname, "./src/assets"), + "@pages": path.resolve(__vite_injected_original_dirname, "./src/pages"), + "@components": path.resolve(__vite_injected_original_dirname, "./src/components"), + "@store": path.resolve(__vite_injected_original_dirname, "./src/store") + } + } +}); +export { + vite_config_default as default +}; +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJDOlxcXFxVc2Vyc1xcXFxNaWNoYWVsXFxcXERlc2t0b3BcXFxcd29ya1xcXFxwcmFnYVxcXFxwYWNrYWdlc1xcXFxjbGllbnRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIkM6XFxcXFVzZXJzXFxcXE1pY2hhZWxcXFxcRGVza3RvcFxcXFx3b3JrXFxcXHByYWdhXFxcXHBhY2thZ2VzXFxcXGNsaWVudFxcXFx2aXRlLmNvbmZpZy50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vQzovVXNlcnMvTWljaGFlbC9EZXNrdG9wL3dvcmsvcHJhZ2EvcGFja2FnZXMvY2xpZW50L3ZpdGUuY29uZmlnLnRzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHJlYWN0IGZyb20gJ0B2aXRlanMvcGx1Z2luLXJlYWN0J1xyXG5pbXBvcnQgZG90ZW52IGZyb20gJ2RvdGVudidcclxuaW1wb3J0IHBhdGggZnJvbSAncGF0aCdcclxuZG90ZW52LmNvbmZpZygpXHJcblxyXG4vLyBodHRwczovL3ZpdGVqcy5kZXYvY29uZmlnL1xyXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVDb25maWcoe1xyXG4gIHNlcnZlcjoge1xyXG4gICAgcG9ydDogTnVtYmVyKHByb2Nlc3MuZW52LkNMSUVOVF9QT1JUKSB8fCAzMDAwLFxyXG4gIH0sXHJcbiAgZGVmaW5lOiB7XHJcbiAgICBfX1NFUlZFUl9QT1JUX186IHByb2Nlc3MuZW52LlNFUlZFUl9QT1JULFxyXG4gIH0sXHJcbiAgc3NyOiB7XHJcbiAgICB0YXJnZXQ6ICdub2RlJyxcclxuICAgIGZvcm1hdDogJ2NqcydcclxuICB9LFxyXG4gIHBsdWdpbnM6IFtyZWFjdCgpXSxcclxuICByZXNvbHZlOiB7XHJcbiAgICBhbGlhczoge1xyXG4gICAgICAnQGFzc2V0cyc6IHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICcuL3NyYy9hc3NldHMnKSxcclxuICAgICAgJ0BwYWdlcyc6IHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICcuL3NyYy9wYWdlcycpLFxyXG4gICAgICAnQGNvbXBvbmVudHMnOiBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCAnLi9zcmMvY29tcG9uZW50cycpLFxyXG4gICAgICAnQHN0b3JlJzogcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4vc3JjL3N0b3JlJyksXHJcbiAgICB9LFxyXG4gIH0sXHJcbn0pXHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBMlYsU0FBUyxvQkFBb0I7QUFDeFgsT0FBTyxXQUFXO0FBQ2xCLE9BQU8sWUFBWTtBQUNuQixPQUFPLFVBQVU7QUFIakIsSUFBTSxtQ0FBbUM7QUFJekMsT0FBTyxPQUFPO0FBR2QsSUFBTyxzQkFBUSxhQUFhO0FBQUEsRUFDMUIsUUFBUTtBQUFBLElBQ04sTUFBTSxPQUFPLFFBQVEsSUFBSSxXQUFXLEtBQUs7QUFBQSxFQUMzQztBQUFBLEVBQ0EsUUFBUTtBQUFBLElBQ04saUJBQWlCLFFBQVEsSUFBSTtBQUFBLEVBQy9CO0FBQUEsRUFDQSxLQUFLO0FBQUEsSUFDSCxRQUFRO0FBQUEsSUFDUixRQUFRO0FBQUEsRUFDVjtBQUFBLEVBQ0EsU0FBUyxDQUFDLE1BQU0sQ0FBQztBQUFBLEVBQ2pCLFNBQVM7QUFBQSxJQUNQLE9BQU87QUFBQSxNQUNMLFdBQVcsS0FBSyxRQUFRLGtDQUFXLGNBQWM7QUFBQSxNQUNqRCxVQUFVLEtBQUssUUFBUSxrQ0FBVyxhQUFhO0FBQUEsTUFDL0MsZUFBZSxLQUFLLFFBQVEsa0NBQVcsa0JBQWtCO0FBQUEsTUFDekQsVUFBVSxLQUFLLFFBQVEsa0NBQVcsYUFBYTtBQUFBLElBQ2pEO0FBQUEsRUFDRjtBQUNGLENBQUM7IiwKICAibmFtZXMiOiBbXQp9Cg== diff --git a/packages/client/vite.config.ts.timestamp-1670430456327.mjs b/packages/client/vite.config.ts.timestamp-1670430456327.mjs new file mode 100644 index 0000000..95c4af9 --- /dev/null +++ b/packages/client/vite.config.ts.timestamp-1670430456327.mjs @@ -0,0 +1,32 @@ +// vite.config.ts +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import dotenv from "dotenv"; +import path from "path"; +var __vite_injected_original_dirname = "C:\\Users\\Michael\\Desktop\\work\\praga\\packages\\client"; +dotenv.config(); +var vite_config_default = defineConfig({ + server: { + port: Number(process.env.CLIENT_PORT) || 3e3 + }, + define: { + __SERVER_PORT__: process.env.SERVER_PORT + }, + ssr: { + target: "node", + format: "cjs" + }, + plugins: [react()], + resolve: { + alias: { + "@assets": path.resolve(__vite_injected_original_dirname, "./src/assets"), + "@pages": path.resolve(__vite_injected_original_dirname, "./src/pages"), + "@components": path.resolve(__vite_injected_original_dirname, "./src/components"), + "@store": path.resolve(__vite_injected_original_dirname, "./src/store") + } + } +}); +export { + vite_config_default as default +}; +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJDOlxcXFxVc2Vyc1xcXFxNaWNoYWVsXFxcXERlc2t0b3BcXFxcd29ya1xcXFxwcmFnYVxcXFxwYWNrYWdlc1xcXFxjbGllbnRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIkM6XFxcXFVzZXJzXFxcXE1pY2hhZWxcXFxcRGVza3RvcFxcXFx3b3JrXFxcXHByYWdhXFxcXHBhY2thZ2VzXFxcXGNsaWVudFxcXFx2aXRlLmNvbmZpZy50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vQzovVXNlcnMvTWljaGFlbC9EZXNrdG9wL3dvcmsvcHJhZ2EvcGFja2FnZXMvY2xpZW50L3ZpdGUuY29uZmlnLnRzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHJlYWN0IGZyb20gJ0B2aXRlanMvcGx1Z2luLXJlYWN0J1xyXG5pbXBvcnQgZG90ZW52IGZyb20gJ2RvdGVudidcclxuaW1wb3J0IHBhdGggZnJvbSAncGF0aCdcclxuZG90ZW52LmNvbmZpZygpXHJcblxyXG4vLyBodHRwczovL3ZpdGVqcy5kZXYvY29uZmlnL1xyXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVDb25maWcoe1xyXG4gIHNlcnZlcjoge1xyXG4gICAgcG9ydDogTnVtYmVyKHByb2Nlc3MuZW52LkNMSUVOVF9QT1JUKSB8fCAzMDAwLFxyXG4gIH0sXHJcbiAgZGVmaW5lOiB7XHJcbiAgICBfX1NFUlZFUl9QT1JUX186IHByb2Nlc3MuZW52LlNFUlZFUl9QT1JULFxyXG4gIH0sXHJcbiAgc3NyOiB7XHJcbiAgICB0YXJnZXQ6ICdub2RlJyxcclxuICAgIGZvcm1hdDogJ2NqcydcclxuICB9LFxyXG4gIHBsdWdpbnM6IFtyZWFjdCgpXSxcclxuICByZXNvbHZlOiB7XHJcbiAgICBhbGlhczoge1xyXG4gICAgICAnQGFzc2V0cyc6IHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICcuL3NyYy9hc3NldHMnKSxcclxuICAgICAgJ0BwYWdlcyc6IHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICcuL3NyYy9wYWdlcycpLFxyXG4gICAgICAnQGNvbXBvbmVudHMnOiBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCAnLi9zcmMvY29tcG9uZW50cycpLFxyXG4gICAgICAnQHN0b3JlJzogcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4vc3JjL3N0b3JlJyksXHJcbiAgICB9LFxyXG4gIH0sXHJcbn0pXHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBMlYsU0FBUyxvQkFBb0I7QUFDeFgsT0FBTyxXQUFXO0FBQ2xCLE9BQU8sWUFBWTtBQUNuQixPQUFPLFVBQVU7QUFIakIsSUFBTSxtQ0FBbUM7QUFJekMsT0FBTyxPQUFPO0FBR2QsSUFBTyxzQkFBUSxhQUFhO0FBQUEsRUFDMUIsUUFBUTtBQUFBLElBQ04sTUFBTSxPQUFPLFFBQVEsSUFBSSxXQUFXLEtBQUs7QUFBQSxFQUMzQztBQUFBLEVBQ0EsUUFBUTtBQUFBLElBQ04saUJBQWlCLFFBQVEsSUFBSTtBQUFBLEVBQy9CO0FBQUEsRUFDQSxLQUFLO0FBQUEsSUFDSCxRQUFRO0FBQUEsSUFDUixRQUFRO0FBQUEsRUFDVjtBQUFBLEVBQ0EsU0FBUyxDQUFDLE1BQU0sQ0FBQztBQUFBLEVBQ2pCLFNBQVM7QUFBQSxJQUNQLE9BQU87QUFBQSxNQUNMLFdBQVcsS0FBSyxRQUFRLGtDQUFXLGNBQWM7QUFBQSxNQUNqRCxVQUFVLEtBQUssUUFBUSxrQ0FBVyxhQUFhO0FBQUEsTUFDL0MsZUFBZSxLQUFLLFFBQVEsa0NBQVcsa0JBQWtCO0FBQUEsTUFDekQsVUFBVSxLQUFLLFFBQVEsa0NBQVcsYUFBYTtBQUFBLElBQ2pEO0FBQUEsRUFDRjtBQUNGLENBQUM7IiwKICAibmFtZXMiOiBbXQp9Cg== diff --git a/packages/client/vite.config.ts.timestamp-1670430526922.mjs b/packages/client/vite.config.ts.timestamp-1670430526922.mjs new file mode 100644 index 0000000..2dd7292 --- /dev/null +++ b/packages/client/vite.config.ts.timestamp-1670430526922.mjs @@ -0,0 +1,32 @@ +// vite.config.ts +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import dotenv from "dotenv"; +import path from "path"; +var __vite_injected_original_dirname = "C:\\Users\\Michael\\Desktop\\work\\Praga\\packages\\client"; +dotenv.config(); +var vite_config_default = defineConfig({ + server: { + port: Number(process.env.CLIENT_PORT) || 3e3 + }, + define: { + __SERVER_PORT__: process.env.SERVER_PORT + }, + ssr: { + target: "node", + format: "cjs" + }, + plugins: [react()], + resolve: { + alias: { + "@assets": path.resolve(__vite_injected_original_dirname, "./src/assets"), + "@pages": path.resolve(__vite_injected_original_dirname, "./src/pages"), + "@components": path.resolve(__vite_injected_original_dirname, "./src/components"), + "@store": path.resolve(__vite_injected_original_dirname, "./src/store") + } + } +}); +export { + vite_config_default as default +}; +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJDOlxcXFxVc2Vyc1xcXFxNaWNoYWVsXFxcXERlc2t0b3BcXFxcd29ya1xcXFxQcmFnYVxcXFxwYWNrYWdlc1xcXFxjbGllbnRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIkM6XFxcXFVzZXJzXFxcXE1pY2hhZWxcXFxcRGVza3RvcFxcXFx3b3JrXFxcXFByYWdhXFxcXHBhY2thZ2VzXFxcXGNsaWVudFxcXFx2aXRlLmNvbmZpZy50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vQzovVXNlcnMvTWljaGFlbC9EZXNrdG9wL3dvcmsvUHJhZ2EvcGFja2FnZXMvY2xpZW50L3ZpdGUuY29uZmlnLnRzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHJlYWN0IGZyb20gJ0B2aXRlanMvcGx1Z2luLXJlYWN0J1xyXG5pbXBvcnQgZG90ZW52IGZyb20gJ2RvdGVudidcclxuaW1wb3J0IHBhdGggZnJvbSAncGF0aCdcclxuZG90ZW52LmNvbmZpZygpXHJcblxyXG4vLyBodHRwczovL3ZpdGVqcy5kZXYvY29uZmlnL1xyXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVDb25maWcoe1xyXG4gIHNlcnZlcjoge1xyXG4gICAgcG9ydDogTnVtYmVyKHByb2Nlc3MuZW52LkNMSUVOVF9QT1JUKSB8fCAzMDAwLFxyXG4gIH0sXHJcbiAgZGVmaW5lOiB7XHJcbiAgICBfX1NFUlZFUl9QT1JUX186IHByb2Nlc3MuZW52LlNFUlZFUl9QT1JULFxyXG4gIH0sXHJcbiAgc3NyOiB7XHJcbiAgICB0YXJnZXQ6ICdub2RlJyxcclxuICAgIGZvcm1hdDogJ2NqcydcclxuICB9LFxyXG4gIHBsdWdpbnM6IFtyZWFjdCgpXSxcclxuICByZXNvbHZlOiB7XHJcbiAgICBhbGlhczoge1xyXG4gICAgICAnQGFzc2V0cyc6IHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICcuL3NyYy9hc3NldHMnKSxcclxuICAgICAgJ0BwYWdlcyc6IHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICcuL3NyYy9wYWdlcycpLFxyXG4gICAgICAnQGNvbXBvbmVudHMnOiBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCAnLi9zcmMvY29tcG9uZW50cycpLFxyXG4gICAgICAnQHN0b3JlJzogcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4vc3JjL3N0b3JlJyksXHJcbiAgICB9LFxyXG4gIH0sXHJcbn0pXHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBMlYsU0FBUyxvQkFBb0I7QUFDeFgsT0FBTyxXQUFXO0FBQ2xCLE9BQU8sWUFBWTtBQUNuQixPQUFPLFVBQVU7QUFIakIsSUFBTSxtQ0FBbUM7QUFJekMsT0FBTyxPQUFPO0FBR2QsSUFBTyxzQkFBUSxhQUFhO0FBQUEsRUFDMUIsUUFBUTtBQUFBLElBQ04sTUFBTSxPQUFPLFFBQVEsSUFBSSxXQUFXLEtBQUs7QUFBQSxFQUMzQztBQUFBLEVBQ0EsUUFBUTtBQUFBLElBQ04saUJBQWlCLFFBQVEsSUFBSTtBQUFBLEVBQy9CO0FBQUEsRUFDQSxLQUFLO0FBQUEsSUFDSCxRQUFRO0FBQUEsSUFDUixRQUFRO0FBQUEsRUFDVjtBQUFBLEVBQ0EsU0FBUyxDQUFDLE1BQU0sQ0FBQztBQUFBLEVBQ2pCLFNBQVM7QUFBQSxJQUNQLE9BQU87QUFBQSxNQUNMLFdBQVcsS0FBSyxRQUFRLGtDQUFXLGNBQWM7QUFBQSxNQUNqRCxVQUFVLEtBQUssUUFBUSxrQ0FBVyxhQUFhO0FBQUEsTUFDL0MsZUFBZSxLQUFLLFFBQVEsa0NBQVcsa0JBQWtCO0FBQUEsTUFDekQsVUFBVSxLQUFLLFFBQVEsa0NBQVcsYUFBYTtBQUFBLElBQ2pEO0FBQUEsRUFDRjtBQUNGLENBQUM7IiwKICAibmFtZXMiOiBbXQp9Cg== diff --git a/packages/server/index.ts b/packages/server/index.ts index 28e9179..e38b334 100644 --- a/packages/server/index.ts +++ b/packages/server/index.ts @@ -5,12 +5,8 @@ import fs from 'fs' import path from 'path' import type { ViteDevServer } from 'vite' import { createServer as createViteServer } from 'vite' -// import queryParser from 'search-query-parser' -// import cookieParser from 'cookie-parser' - import sequelize from './sequelize' import router from './router' -// import { userThemeRouter } from './controllers/userTheme' dotenv.config() @@ -22,11 +18,8 @@ async function createServer(isDev = process.env.NODE_ENV === 'development') { const app = express() app.disable('x-powered-by').enable('trust proxy') - // .set('query parser', queryParser) - // .use(cookieParser()) - // .use(logger) - // .use(router) - // .use(notFound); + + let vite: ViteDevServer diff --git a/packages/server/package.json b/packages/server/package.json index e6f7c31..0aecc47 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -6,6 +6,7 @@ "build": "rm -rf ./dist && tsc --p ./tsconfig.prod.json", "preview": "node ./dist/index.js", "dev": "cross-env NODE_ENV=development nodemon index.ts", + "serve": "yarn build && yarn preview", "lint": "eslint .", "format": "prettier --write .", "test": "jest ." diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json index ad2f262..77f7451 100644 --- a/packages/server/tsconfig.json +++ b/packages/server/tsconfig.json @@ -21,12 +21,21 @@ "experimentalDecorators": true, "emitDecoratorMetadata": true, "strictPropertyInitialization": false, - "lib": ["es2019", "esnext.asynciterable", "dom"], - "types": ["node", "jest"], + "lib": [ + "es2019", + "esnext.asynciterable", + "dom" + ], + "types": [ + "node", + "jest" + ], "baseUrl": ".", "paths": { - "*": ["types/*"] + "*": [ + "types/*" + ] }, "outDir": "dist" } -} +} \ No newline at end of file