non auth part
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import {useEffect, useState} from "react";
|
||||
import {useEffect, useMemo, useState} from "react";
|
||||
import {DEBUG_MODE} from "../utils/common";
|
||||
import {ApiResponse, PageResponse} from "../types/api.ts";
|
||||
import {PageControl} from "../types/common.ts";
|
||||
import {Institution} from "../types/survey.ts";
|
||||
|
||||
export function hostUrl(url: string){
|
||||
return DEBUG_MODE? "http://localhost:8000"+url: url;
|
||||
@@ -144,3 +145,43 @@ export function useData<T>(application:string, endpoint: string, id: string|numb
|
||||
|
||||
}
|
||||
|
||||
export function useCachedData<T>(application: string, endpoint: string) {
|
||||
const [cache, setCache] = useState<Map<string | number, T | undefined>>(new Map());
|
||||
|
||||
useEffect(() => {
|
||||
// Очистка кеша или другие побочные эффекты при необходимости
|
||||
return () => {
|
||||
setCache(new Map());
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (id: string | number, needLoad: boolean = true): T | undefined | null => {
|
||||
const cachedData = cache.has(id)?cache.get(id):null;
|
||||
|
||||
if (cachedData !== null) {
|
||||
return cachedData;
|
||||
}
|
||||
|
||||
if (needLoad) {
|
||||
getFetch(`/${application}/${endpoint}/${id}`).then((r) => {
|
||||
if (r.success) {
|
||||
const data = r.body as T;
|
||||
setCache((prevCache) => {
|
||||
const newCache = new Map(prevCache);
|
||||
newCache.set(id, data);
|
||||
return newCache;
|
||||
});
|
||||
} else {
|
||||
setCache((prevCache) => {
|
||||
const newCache = new Map(prevCache);
|
||||
newCache.set(id, undefined);
|
||||
return newCache;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {ReactElement} from "react";
|
||||
import {UniqueItem} from "../types/common.ts";
|
||||
import {JSX} from "react";
|
||||
|
||||
export function LoadingList({data, listElement}: {data: UniqueItem[]|null, listElement(e:UniqueItem, i:number):ReactElement}) {
|
||||
export function LoadingList({data, listElement}: {data: UniqueItem[]|null, listElement(e:UniqueItem, i:number):unknown}) {
|
||||
if (data === null){
|
||||
return <div className={"loading"}>Идёт загрузка...</div>
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useData, useDataPage } from '../API/common';
|
||||
import {Link, useParams} from 'react-router-dom';
|
||||
import {useCachedData, useData, useDataPage} from '../API/common';
|
||||
import { Institution, Profession, Specialty } from '../types/survey';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import { LoadingData } from '../components/LoadingData';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { LoadingList } from '../components/LoadingList';
|
||||
|
||||
|
||||
@@ -13,29 +12,7 @@ export function ProfessionPage() {
|
||||
const profession = useData<Profession>('surveys', 'professions', professionId || 0);
|
||||
const specialties = useDataPage<Specialty>('surveys', 'specialties', { profession: professionId || 0 }, !!profession);
|
||||
|
||||
const [institutionCache, setInstitutionCache] = useState<Map<number, Institution>>(new Map()); // Кеширование учебных заведений
|
||||
const institutionsToLoad = useMemo(() => {
|
||||
if (!specialties.items) return [];
|
||||
return specialties.items
|
||||
.map(specialty => specialty.institution)
|
||||
.filter(id => !institutionCache.has(id));
|
||||
}, [specialties.items, institutionCache]);
|
||||
|
||||
useEffect(() => {
|
||||
if (institutionsToLoad.length > 0) {
|
||||
Promise.all(
|
||||
institutionsToLoad.map(id =>
|
||||
useData<Institution>('surveys', 'institutions', id, true)
|
||||
)
|
||||
).then(newInstitutions => {
|
||||
setInstitutionCache(prev => {
|
||||
const newCache = new Map(prev);
|
||||
newInstitutions.forEach(institution => institution && newCache.set(institution.id, institution));
|
||||
return newCache;
|
||||
});
|
||||
});
|
||||
}
|
||||
}, [institutionsToLoad]);
|
||||
const institutions = useCachedData<Institution>("surveys", "institutions");
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -45,14 +22,14 @@ export function ProfessionPage() {
|
||||
<ReactMarkdown>{profession?.description || ''}</ReactMarkdown>
|
||||
</div>
|
||||
<div className="specialties-block">
|
||||
<h2>Где можно обучиться</h2>
|
||||
{specialties.items != null ? <h2>Где можно обучиться</h2>:null}
|
||||
<LoadingList
|
||||
data={specialties.items}
|
||||
listElement={(specialty) => (
|
||||
listElement={specialty => (
|
||||
<SpecialtyBlock
|
||||
key={specialty.id}
|
||||
specialty={specialty as Specialty}
|
||||
institution={institutionCache.get((specialty as Specialty).institution)}
|
||||
institution={institutions((specialty as Specialty).institution)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@@ -67,12 +44,14 @@ function SpecialtyBlock({
|
||||
institution,
|
||||
}: {
|
||||
specialty: Specialty;
|
||||
institution: Institution | undefined;
|
||||
institution: Institution | undefined | null;
|
||||
}) {
|
||||
return (
|
||||
<div className="specialty-block">
|
||||
<h3>{specialty.name}</h3>
|
||||
<p>Учебное заведение: {institution?.name || 'Загрузка...'}</p>
|
||||
<h3>Учебное заведение: {institution?.name || 'Загрузка...'}</h3>
|
||||
<p className={"specialty-name"}>{specialty.name}</p>
|
||||
{specialty.link?<Link to={specialty.link} className={"site"}>Открыть сайт</Link>:null}
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -106,9 +106,11 @@ export function SurveyPage() {
|
||||
/>
|
||||
)} />
|
||||
|
||||
{isCompleted && (
|
||||
<button onClick={calculateResults}>Завершить тест</button>
|
||||
)}
|
||||
<>
|
||||
{isCompleted && (
|
||||
<button onClick={calculateResults}>Завершить тест</button>
|
||||
)}
|
||||
</>
|
||||
</LoadingData>
|
||||
</div>
|
||||
);
|
||||
@@ -125,7 +127,7 @@ function QuestionBlock({
|
||||
}) {
|
||||
switch (question.questionType) {
|
||||
case QuestionType.AgreementQuestion:
|
||||
const agreementQuestion = question as AgreementQuestion;
|
||||
{ const agreementQuestion = question as AgreementQuestion;
|
||||
return (
|
||||
<div className={`question agreement ${answered !== undefined ? "answered" : "unanswered"}`}>
|
||||
{agreementQuestion.question}
|
||||
@@ -139,10 +141,10 @@ function QuestionBlock({
|
||||
onClick={() => onAnswer(`${question.questionType}_${question.id}`, 0)}>Не согласен</button>
|
||||
|
||||
</div>
|
||||
);
|
||||
); }
|
||||
|
||||
case QuestionType.QuestionPair:
|
||||
const pairQuestion = question as QuestionPair;
|
||||
{ const pairQuestion = question as QuestionPair;
|
||||
return (
|
||||
<div className={`question pair ${answered !== undefined ? "answered" : "unanswered"}`}>
|
||||
{pairQuestion.statements.map((statement) => (
|
||||
@@ -156,7 +158,7 @@ function QuestionBlock({
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
); }
|
||||
|
||||
default:
|
||||
return null;
|
||||
|
||||
@@ -9,4 +9,8 @@ export interface PageControl<T>{
|
||||
hasPrevious: boolean;
|
||||
nextPage(): void;
|
||||
previousPage(): void;
|
||||
}
|
||||
}
|
||||
|
||||
export interface CachedData<T>{
|
||||
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ export interface Profession extends UniqueItem {
|
||||
export interface Specialty extends UniqueItem {
|
||||
name: string;
|
||||
institution: number;
|
||||
profession: number;
|
||||
link?: string;
|
||||
}
|
||||
|
||||
export interface Institution extends UniqueItem {
|
||||
|
||||
Reference in New Issue
Block a user