Skip to content

Commit

Permalink
Merge branch 'frontend' into cards-users
Browse files Browse the repository at this point in the history
  • Loading branch information
semant1cs committed Nov 28, 2023
2 parents 17bbb2f + 205afc9 commit 725b157
Show file tree
Hide file tree
Showing 37 changed files with 654 additions and 394 deletions.
2 changes: 1 addition & 1 deletion backend/migrations/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
# target_metadata = mymodel.Base.metadata

from game.map import Map
from game.modules import Module
from game.modules import Level
from game.levels import Level
from game.units.tasks import TaskUnit, EmployeeTask
from game.units.theory import TheoryUnit # , TheoryVideo
Expand Down
4 changes: 2 additions & 2 deletions backend/src/game/levels/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from game.units import TaskUnit, TheoryUnit

if typing.TYPE_CHECKING:
from game.modules.models import Module
from game.modules.models import Level
from game.units.tasks.models import TaskUnit
from game.units.theory.models import TheoryUnit

Expand All @@ -23,7 +23,7 @@ class Level(BaseModel):
module_id: Mapped[uuid.UUID] = mapped_column(UUID, ForeignKey('modules.id'))
title: Mapped[str] = mapped_column(String(length=255), nullable=False)

module: Mapped["Module"] = relationship(back_populates='levels')
module: Mapped["Level"] = relationship(back_populates='levels')

theory_units: Mapped[list["TheoryUnit"]] = relationship(back_populates='level', lazy='selectin')

Expand Down
4 changes: 2 additions & 2 deletions backend/src/game/map/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from game.map.schemas import MapRead, MapCreate

if typing.TYPE_CHECKING:
from game.modules.models import Module
from game.modules.models import Level


class Map(BaseModel):
Expand All @@ -18,7 +18,7 @@ class Map(BaseModel):
id: Mapped[uuid.UUID] = mapped_column(UUID, primary_key=True, default=uuid.uuid4)
title: Mapped[str] = mapped_column(String(length=255), nullable=False)

modules: Mapped[list["Module"]] = relationship(back_populates='map', lazy='selectin')
modules: Mapped[list["Level"]] = relationship(back_populates='map', lazy='selectin')
modules_ids: AssociationProxy[list[uuid.UUID]] = association_proxy('modules', 'id')

def to_read_schema(self) -> MapRead:
Expand Down
2 changes: 1 addition & 1 deletion backend/src/game/modules/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .models import Module
from .models import Level
2 changes: 1 addition & 1 deletion backend/src/game/modules/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from game.map import Map


class Module(BaseModel):
class Level(BaseModel):
__tablename__ = 'modules'

id: Mapped[uuid.UUID] = mapped_column(UUID, primary_key=True, default=uuid.uuid4)
Expand Down
2 changes: 1 addition & 1 deletion backend/src/game/modules/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from game.modules.schemas import ModuleRead, ModuleCreate, ModuleUpdate
from utils.types import ModuleServiceType

router = APIRouter(tags=["Module"])
router = APIRouter(tags=["Level"])


@router.get("/modules/", tags=["Dev"])
Expand Down
4 changes: 2 additions & 2 deletions backend/src/repository/module_repository.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from game.modules import Module
from game.modules import Level
from repository.sqlalchemy_repository import SQLAlchemyRepository


class ModuleRepository(SQLAlchemyRepository):
model = Module
model = Level
15 changes: 15 additions & 0 deletions frontend/src/UIComponents/modalWindow/HeaderModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';

interface IHeaderModal {
body: React.ReactNode
}

const HeaderModal: React.FC<IHeaderModal> = ({body}) => {
return (
<div className="header-modal">
{body}
</div>
);
};

export default HeaderModal;
35 changes: 35 additions & 0 deletions frontend/src/components/authentication/AuthForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import CustomInput from "../../UIComponents/customInput/CustomInput.tsx";
import authStore from "../../store/authStore.ts";
import CustomCheckbox from "../../UIComponents/customCheckbox/CustomCheckbox.tsx";
import CustomButton from "../../UIComponents/customButton/CustomButton.tsx";
import {useNavigate} from "react-router-dom"
import {observer} from "mobx-react-lite";

const AuthForm: React.FC = observer(() => {
const navigateTo = useNavigate()

return (
<form className="auth__form">
<h2 className="auth-form-title">ВХОД</h2>
<fieldset className="auth-fields">
<CustomInput type="email" value={authStore.userLogin} autoFocus={true} placeholder="Логин"
handleOnChange={(e) => {
authStore.changeUserLogin(e)
authStore.changeUserEmail(e)
}}/>
<CustomInput
type={authStore.isPasswordShows ? "text" : "password"} placeholder="Пароль"
value={authStore.userPassword} handleOnChange={(e) => authStore.changeUserPassword(e)}/>
</fieldset>
<CustomCheckbox text="Показать пароль" id="is-remember"
additionalClassName="is-remember-password__checkbox"
handleOnChange={authStore.changeIsPasswordShows}/>
<CustomButton additionalClassName="auth__btn" text="ВОЙТИ" handleOnClick={() => {
authStore.signIn().then(() => navigateTo('/map'))
}}/>
</form>
);
});

export default AuthForm;
40 changes: 5 additions & 35 deletions frontend/src/components/authentication/Authentication.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,19 @@
import React, {useState} from 'react';
import React from 'react';
import './../../styles/authentication.scss'
import CustomButton from "../../UIComponents/customButton/CustomButton.tsx";
import CustomCheckbox from "../../UIComponents/customCheckbox/CustomCheckbox.tsx";
import authStore from "../../store/authStore.ts";
import {observer} from "mobx-react-lite";
import {useNavigate} from "react-router-dom";
import CustomInput from "../../UIComponents/customInput/CustomInput.tsx";
import AuthForm from "./AuthForm.tsx";

const Authentication: React.FC = observer(() => {
const Authentication: React.FC = () => {
const navigateTo = useNavigate()

const [isPasswordShows, setIsPasswordShow] = useState(false)

const changeShowPassword = () => {
setIsPasswordShow(!isPasswordShows)
}


return (
<div className="auth-page">
<form className="auth__form">
<h2 className="auth-form-title">ВХОД</h2>
<fieldset className="auth-fields">
<CustomInput type="email" value={authStore.userLogin} handleOnChange={(e) => {
authStore.changeUserLogin(e)
authStore.changeUserEmail(e)
}}
autoFocus={true} placeholder="Логин"/>
<div className="auth-data__field">
<CustomInput type={isPasswordShows ? "text" : "password"} placeholder="Пароль"
value={authStore.userPassword}
handleOnChange={(e) => authStore.changeUserPassword(e)}/>
</div>
</fieldset>
<CustomCheckbox text="Показать пароль" id="is-remember"
additionalClassName="is-remember-password__checkbox"
handleOnChange={changeShowPassword}/>
<CustomButton additionalClassName="auth__btn" text="ВОЙТИ" handleOnClick={() => {
authStore.signIn().then(() => navigateTo('/map'))
}}/>
</form>
<AuthForm/>
<CustomButton additionalClassName="back-to-welcome-page__btn" text="Вернуться обратно"
handleOnClick={() => navigateTo('/')}></CustomButton>
</div>
);
});
};

export default Authentication;
48 changes: 48 additions & 0 deletions frontend/src/components/mapMenu/EmployeeMap/EmployeeMap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React, {useEffect} from 'react';
import Coins from "../UIMapMenu/Coins.tsx";
import ChooseModuleWindow from "../UIMapMenu/ChooseModuleWindow.tsx";
import mapMenuStore from "../../../store/mapMenuStore.ts";
import UserProfile from "../UIMapMenu/UserProfile/UserProfile.tsx";
import Level from "../UIMapMenu/Level/Level.tsx";
import {IUserType} from "../../../types/UserType.ts";
import {observer} from "mobx-react-lite";
import moduleMenuStore from "../../../store/moduleMenuStore.ts";

interface IEmployeeMap {
user?: IUserType,
formattedDate: string
}

const EmployeeMap: React.FC<IEmployeeMap> = observer(({user, formattedDate}) => {
useEffect(() => {
mapMenuStore.fetchAvailableMaps().then(() => {
mapMenuStore.fetchMapById(mapMenuStore.availableMaps[0].id).then(() => {
moduleMenuStore.fetchModules().then(() => {
moduleMenuStore.fetchModuleById(moduleMenuStore.availableModules[0].id).then(() => {
mapMenuStore.fetchLevels().then(() => {

}).catch(() => alert("Нет доступных уровней для данного модуля"))
})
}).catch(() => alert("Нет доступных модулей для данной карты"))
})
}).catch(() => alert("Нет доступных карт для данного пользователя"))
}, []);

return (
<div className="employee-interface">
<Coins coins={100} additionalClassname="coins"/>
<ChooseModuleWindow moduleName={moduleMenuStore.currentModule?.title}/>
<UserProfile user={user} formattedDate={formattedDate}/>
<div className="geolocations">
<div className="geolocations__wrapper">
{mapMenuStore.availableLevels.map((level, index) => {
return <Level id={(index + 1).toString()} key={level.id} title={level.title}
theoryUnits={level.theoryUnits} taskUnits={level.taskUnits}/>
})}
</div>
</div>
</div>
);
});

export default EmployeeMap;
55 changes: 10 additions & 45 deletions frontend/src/components/mapMenu/MapMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
import React, {useEffect, useState} from 'react';
import authStore from "../../store/authStore.ts";
import {useNavigate} from "react-router-dom";
import Coins from "./UIMapMenu/Coins.tsx";
import './../../styles/mapMenu.scss'
import ChooseModuleWindow from "./UIMapMenu/ChooseModuleWindow.tsx";
import UserProfile from "./UIMapMenu/UserProfile/UserProfile.tsx";
import Module from "./UIMapMenu/Level/Module.tsx";
import mapMenuStore from "../../store/mapMenuStore.ts";
import {observer} from "mobx-react-lite";
import {IUserType} from "../../types/UserType.ts";
import axios from "axios";
import EmployeeMap from "./EmployeeMap/EmployeeMap.tsx";
import SuperUserMap from "./SuperUserMap/SuperUserMap.tsx";
import superUserStore from "../../store/superUserStore.ts";

const MapMenu: React.FC = observer(() => {
const navigate = useNavigate()

const [user, setUser] = useState<IUserType>()
const [formattedDate, setFormattedDate] = useState("")
const [allUsers, setAllUsers] = useState<IUserType[]>()


useEffect(() => {
axios.get("http://localhost:8000/users/").then((response) => {
Expand All @@ -26,10 +24,10 @@ const MapMenu: React.FC = observer(() => {
}
})

setAllUsers(response.data)
superUserStore.setAllUsers(response.data)


if (user) {
console.log(user)
const date = new Date(Date.parse(user!.registered_at))
setFormattedDate(`${date.getDay()}.${date.getMonth()}.${date.getUTCFullYear()}`)
}
Expand All @@ -39,47 +37,14 @@ const MapMenu: React.FC = observer(() => {
useEffect(() => {
if (!authStore.isUserAuthorized)
navigate("/")

mapMenuStore.fetchAvailableMaps().then(() => {
mapMenuStore.fetchMapById(mapMenuStore.availableMaps[0].id).then(() => {
mapMenuStore.fetchModules().then(() => {
mapMenuStore.fetchModuleById(mapMenuStore.availableModules[0].id).then(() => {
mapMenuStore.fetchLevels().then(() => {

}).catch(() => alert("Нет доступных уровней для данного модуля"))
})
}).catch(() => alert("Нет доступных модулей для данной карты"))
})
}).catch(() => alert("Нет доступных карт для данного пользователя"))
}, [navigate])

return (
<div>
{user?.is_superuser
? (
<div>
<select>
{allUsers?.map((user) =>
<option key={user.username} value={user.username}>{user.username}</option>)}
</select>
</div>
) : (
<div className="employee-interface">
{/*<Coins coins={100} additionalClassname="coins"/>*/}
<ChooseModuleWindow moduleName={mapMenuStore.currentModule?.title}/>
<UserProfile user={user} formattedDate={formattedDate}/>
<br/>
<div className="geolocations">
<div className="geolocations__wrapper">
{mapMenuStore.availableLevels.map((level, index) => {
return <Module id={(index + 1).toString()} key={level.id} title={level.title}
theoryUnits={level.theoryUnits} taskUnits={level.taskUnits}/>
})}
</div>
</div>
</div>
)}

{!user?.is_superuser
? <SuperUserMap/>
: <EmployeeMap user={user} formattedDate={formattedDate}/>
}
</div>
);
});
Expand Down
60 changes: 60 additions & 0 deletions frontend/src/components/mapMenu/SuperUserMap/SuperUserMap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React, {useEffect, useState} from 'react';
import CustomButton from "../../../UIComponents/customButton/CustomButton.tsx";
import mapMenuStore from "../../../store/mapMenuStore.ts";
import CustomInput from "../../../UIComponents/customInput/CustomInput.tsx";
import {observer} from "mobx-react-lite";
import superUserStore from "../../../store/superUserStore.ts";
import moduleMenuStore from "../../../store/moduleMenuStore.ts";
import {IMapType} from "../../../types/MapType.ts";

interface ISuperUserMap {

}

const SuperUserMap: React.FC<ISuperUserMap> = observer(() => {
const [isUsersListModalOpen, setIsUserListModalOpen] = useState<boolean>(false)

useEffect(() => {
mapMenuStore.fetchAvailableMaps()
.then(() => mapMenuStore.fetchMapById(mapMenuStore.availableMaps[mapMenuStore.currentMapIndex].id)
.then(() => moduleMenuStore.fetchModules()))
}, []);

function handleOnClickOptionMap(map: IMapType, indexMap: number) {
mapMenuStore.selectMap(map).then(() => mapMenuStore.changeCurrentMapIndex(indexMap))
}


return (
<div>
<form>
<select>
{superUserStore.allUsers.map((user) =>
<option key={user.username} value={user.username}>{user.username}</option>)}
</select>

<div className="map-create">
<CustomInput type="text" value={mapMenuStore.newNameMap}
handleOnChange={(e) => mapMenuStore.changeNewMapName(e)}/>
<CustomButton text="Создать новую карту"
handleOnClick={() => mapMenuStore.createMap(mapMenuStore.newNameMap)}/>
</div>

<select className="available-maps">
{mapMenuStore.availableMaps?.map((map, index) =>
<option key={map.id} value={map.title}
onClick={() => handleOnClickOptionMap(map, index)}>{map.title}</option>)}
<CustomButton text="Удалить выбранную карту" additionalClassName="delete-map__btn"
handleOnClick={() => mapMenuStore.deleteMap(mapMenuStore.mapMenu?.id)}/>
</select>

<select className="available-modules">
{moduleMenuStore.availableModules.map((module) =>
<option key={module.id} value={module.title}>{module.title}</option>)}
</select>
</form>
</div>
);
});

export default SuperUserMap;
Loading

0 comments on commit 725b157

Please sign in to comment.