get lessons list

This commit is contained in:
Primakov Alexandr Alexandrovich 2024-02-29 09:18:13 +03:00
parent 5134d44e39
commit 80713f7e0f
7 changed files with 72 additions and 54 deletions

View File

@ -16,8 +16,6 @@ module.exports = {
}, },
}, },
config: { config: {
"journal.socket.url": "ws://localhost",
"journal.socket.path": "/socket.io/",
"journal.back.url": "/api", "journal.back.url": "/api",
} }
} }

View File

@ -2,6 +2,7 @@ import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { getConfigValue } from "@ijl/cli"; import { getConfigValue } from "@ijl/cli";
import { keycloak } from "../kc"; import { keycloak } from "../kc";
import { BaseResponse, Lesson } from "../model";
export const api = createApi({ export const api = createApi({
reducerPath: "auth", reducerPath: "auth",
@ -13,7 +14,7 @@ export const api = createApi({
}, },
}), }),
endpoints: (builder) => ({ endpoints: (builder) => ({
lessonList: builder.query({ lessonList: builder.query<BaseResponse<Lesson[]>, void>({
query: () => '/lesson/list' query: () => '/lesson/list'
}) })
// signIn: builder.mutation<SignInResponce, SignInRequestBody>({ // signIn: builder.mutation<SignInResponce, SignInRequestBody>({

View File

@ -11,7 +11,7 @@ interface TokenData {
nonce: string; nonce: string;
session_state: string; session_state: string;
acr: string; acr: string;
'allowed-origins': string[]; "allowed-origins": string[];
realm_access: Realmaccess; realm_access: Realmaccess;
resource_access: Resourceaccess; resource_access: Resourceaccess;
scope: string; scope: string;
@ -25,25 +25,34 @@ interface TokenData {
} }
interface Resourceaccess { interface Resourceaccess {
'realm-management': Realmaccess; journal: Realmaccess;
jurnal: Realmaccess;
broker: Realmaccess;
account: Realmaccess;
'microfrontend-admin': Realmaccess
} }
interface Realmaccess { interface Realmaccess {
roles: string[]; roles: (string | "teacher")[];
} }
export interface UserData extends TokenData { export interface UserData extends TokenData {
sub: string; sub: string;
gravatar: string; gravatar: string;
email_verified: boolean; email_verified: boolean;
attributes: Record<string, string[]> attributes: Record<string, string[]>;
name: string; name: string;
preferred_username: string; preferred_username: string;
given_name: string; given_name: string;
family_name: string; family_name: string;
email: string; email: string;
} }
export type BaseResponse<Data> = {
success: boolean;
body: Data;
};
export interface Lesson {
_id: string;
name: string;
students: any[];
date: string;
created: string;
}

View File

@ -1,4 +1,5 @@
import { configureStore } from '@reduxjs/toolkit'; import { configureStore } from '@reduxjs/toolkit';
import { TypedUseSelectorHook, useSelector } from 'react-redux';
import { api } from './api/api'; import { api } from './api/api';
import { userSlice } from './slices/user'; import { userSlice } from './slices/user';
@ -14,3 +15,5 @@ export const createStore= (preloadedState = {}) => configureStore({
}); });
export type Store = ReturnType<ReturnType<typeof createStore>['getState']>; export type Store = ReturnType<ReturnType<typeof createStore>['getState']>;
export const useAppSelector: TypedUseSelectorHook<Store> = useSelector;

View File

@ -1,13 +1,15 @@
import React from "react"; import React from 'react';
import ReactDom from "react-dom"; import ReactDOM from 'react-dom/client';
import App from "./app"; import App from './app';
import { keycloak } from "./__data__/kc"; import { keycloak } from "./__data__/kc";
import { createStore } from "./__data__/store"; import { createStore } from "./__data__/store";
export default (props) => <App {...props} />; export default (props) => <App {...props} />;
export const mount = async (Сomponent) => { let rootElement: ReactDOM.Root
export const mount = async (Сomponent, element = document.getElementById('app')) => {
let user = null; let user = null;
try { try {
await keycloak.init({ onLoad: "login-required" }); // 'login-required' }); await keycloak.init({ onLoad: "login-required" }); // 'login-required' });
@ -18,15 +20,16 @@ export const mount = async (Сomponent) => {
} }
const store = createStore({ user }); const store = createStore({ user });
ReactDom.render(<Сomponent store={store} />, document.getElementById("app")); const rootElement = ReactDOM.createRoot(element);
rootElement.render(<Сomponent store={store} />);
if (module.hot) { if(module.hot) {
module.hot.accept("./app", () => { module.hot.accept('./app', ()=> {
ReactDom.render(<App store={store} />, document.getElementById("app")); rootElement.render(<Сomponent store={store} />);
}); })
} }
}; };
export const unmount = () => { export const unmount = () => {
ReactDom.unmountComponentAtNode(document.getElementById("app")); rootElement.unmount();
}; };

View File

@ -16,9 +16,14 @@ import {
import arrow from "../assets/36-arrow-right.svg"; import arrow from "../assets/36-arrow-right.svg";
import { keycloak } from "../__data__/kc"; import { keycloak } from "../__data__/kc";
import { useAppSelector } from "../__data__/store";
import { api } from '../__data__/api/api'
import { isTeacher } from "../utils/user";
export const Journal = () => { export const Journal = () => {
const [lessons, setLessons] = useState(null); const [lessons, setLessons] = useState(null);
const user = useAppSelector((s) => s.user);
const { data, isLoading, error } = api.useLessonListQuery();
useEffect(() => { useEffect(() => {
const check = async () => { const check = async () => {
@ -34,7 +39,7 @@ export const Journal = () => {
console.log("check", data); console.log("check", data);
} else { } else {
keycloak.onAuthSuccess = check keycloak.onAuthSuccess = check;
} }
}; };
@ -55,9 +60,9 @@ export const Journal = () => {
const data = await rq.json(); const data = await rq.json();
setAnswer(data); setAnswer(data);
} else { } else {
setAnswer({ message: 'Пользователь не авторизован' }) setAnswer({ message: "Пользователь не авторизован" });
} }
} };
const [value, setValue] = useState(""); const [value, setValue] = useState("");
const handleChange = useCallback( const handleChange = useCallback(
@ -81,36 +86,32 @@ export const Journal = () => {
return ( return (
<StartWrapper> <StartWrapper>
<div> {isTeacher(user) && (
<IconButton onClick={send} title="Запрос"> <form onSubmit={handleSubmit}>
<ArrowImg src={arrow} /> <InputWrapper>
</IconButton> <InputLabel htmlFor="input">Название новой лекции:</InputLabel>
<pre>{JSON.stringify(answer, null, 4)}</pre> <InputElement
</div> value={value}
<form onSubmit={handleSubmit}> onChange={handleChange}
<InputWrapper> ref={inputRef}
<InputLabel htmlFor="input">Название новой лекции:</InputLabel> id="input"
<InputElement type="text"
value={value} autoComplete="off"
onChange={handleChange} />
ref={inputRef} <IconButton type="submit">
id="input" <ArrowImg src={arrow} />
type="text" </IconButton>
autoComplete="off" </InputWrapper>
/> </form>
<IconButton type="submit"> )}
<ArrowImg src={arrow} />
</IconButton>
</InputWrapper>
</form>
<ul style={{ paddingLeft: 0 }}> <ul style={{ paddingLeft: 0 }}>
{lessons?.map((lesson) => ( {data?.body?.map((lesson) => (
<LessonItem key={lesson.id}> <LessonItem key={lesson._id}>
<Link to={`/journal/l/${lesson.id}`} style={{ display: "flex" }}> <Link to={isTeacher(user) ? `/journal/l/${lesson._id}` : ''} style={{ display: "flex" }}>
<Lessonname>{lesson.name}</Lessonname> <Lessonname>{lesson.name}</Lessonname>
<span>{dayjs(lesson.ts).format("DD MMMM YYYYг.")}</span> <span>{dayjs(lesson.date).format("DD MMMM YYYYг.")}</span>
<span style={{ marginLeft: "auto" }}> <span style={{ marginLeft: "auto" }}>
Участников - {lesson.padavans.length} Участников - {lesson.students.length}
</span> </span>
</Link> </Link>
</LessonItem> </LessonItem>

3
src/utils/user.ts Normal file
View File

@ -0,0 +1,3 @@
import { UserData } from "../__data__/model";
export const isTeacher = (user?: UserData): boolean => user?.resource_access?.journal?.roles?.includes('teacher')