Stuff
This commit is contained in:
parent
c0ad0826d0
commit
9dbdde6baa
@ -130,6 +130,7 @@ export interface InternshipInfoDTO extends Identifiable {
|
|||||||
export const internshipReportDtoTransformer: OneWayTransformer<InternshipReportDTO, Report> = {
|
export const internshipReportDtoTransformer: OneWayTransformer<InternshipReportDTO, Report> = {
|
||||||
transform(subject: InternshipReportDTO, context?: unknown): Report {
|
transform(subject: InternshipReportDTO, context?: unknown): Report {
|
||||||
return {
|
return {
|
||||||
|
id: subject.id,
|
||||||
fields: JSON.parse(subject.value),
|
fields: JSON.parse(subject.value),
|
||||||
...statefulDtoTransformer.transform(subject),
|
...statefulDtoTransformer.transform(subject),
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ export type ReportFieldValues = { [field: string]: ReportFieldValue };
|
|||||||
export type ReportSchema = ReportFieldDefinition[];
|
export type ReportSchema = ReportFieldDefinition[];
|
||||||
export type ReportFieldType = ReportFieldDefinition['type'];
|
export type ReportFieldType = ReportFieldDefinition['type'];
|
||||||
|
|
||||||
export interface Report extends Stateful {
|
export interface Report extends Stateful, Identifiable {
|
||||||
fields: ReportFieldValues;
|
fields: ReportFieldValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@ import { axios } from "@/api";
|
|||||||
import { prepare } from "@/routing";
|
import { prepare } from "@/routing";
|
||||||
import { InternshipDocument } from "@/api/dto/internship-registration";
|
import { InternshipDocument } from "@/api/dto/internship-registration";
|
||||||
|
|
||||||
const DOCUMENT_ACCEPT_ENDPOINT = "/management/document/accept/:id";
|
const DOCUMENT_ACCEPT_ENDPOINT = "/management/document/:id/accept";
|
||||||
const DOCUMENT_REJECT_ENDPOINT = "/management/document/reject/:id";
|
const DOCUMENT_REJECT_ENDPOINT = "/management/document/:id/reject";
|
||||||
|
|
||||||
export async function accept(document: OneOrMany<InternshipDocument>, comment?: string): Promise<void> {
|
export async function accept(document: OneOrMany<InternshipDocument>, comment?: string): Promise<void> {
|
||||||
const documents = encapsulate(document)
|
const documents = encapsulate(document)
|
||||||
|
@ -5,6 +5,7 @@ import * as course from "./course"
|
|||||||
import * as internship from "./internship"
|
import * as internship from "./internship"
|
||||||
import * as document from "./document"
|
import * as document from "./document"
|
||||||
import * as field from "./field"
|
import * as field from "./field"
|
||||||
|
import * as report from "./report"
|
||||||
|
|
||||||
export const api = {
|
export const api = {
|
||||||
edition,
|
edition,
|
||||||
@ -13,7 +14,8 @@ export const api = {
|
|||||||
course,
|
course,
|
||||||
internship,
|
internship,
|
||||||
document,
|
document,
|
||||||
field
|
field,
|
||||||
|
report
|
||||||
}
|
}
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
InternshipDocument,
|
InternshipDocument,
|
||||||
InternshipDocumentDTO,
|
InternshipDocumentDTO,
|
||||||
internshipDocumentDtoTransformer,
|
internshipDocumentDtoTransformer,
|
||||||
InternshipInfoDTO,
|
InternshipInfoDTO, internshipReportDtoTransformer,
|
||||||
submissionStateDtoTransformer
|
submissionStateDtoTransformer
|
||||||
} from "@/api/dto/internship-registration";
|
} from "@/api/dto/internship-registration";
|
||||||
import { Transformer } from "@/serialization";
|
import { Transformer } from "@/serialization";
|
||||||
@ -17,22 +17,25 @@ import { internshipTypeDtoTransformer } from "@/api/dto/type";
|
|||||||
import { studentDtoTransfer } from "@/api/dto/student";
|
import { studentDtoTransfer } from "@/api/dto/student";
|
||||||
import { programEntryDtoTransformer } from "@/api/dto/edition";
|
import { programEntryDtoTransformer } from "@/api/dto/edition";
|
||||||
import { UploadType } from "@/api/upload";
|
import { UploadType } from "@/api/upload";
|
||||||
|
import { Report } from "@/data/report";
|
||||||
|
|
||||||
export type InternshipSubmission = Nullable<Internship> & {
|
export type InternshipSubmission = Nullable<Internship> & {
|
||||||
state: SubmissionStatus,
|
state: SubmissionStatus,
|
||||||
changed: Moment | null,
|
changed: Moment | null,
|
||||||
ipp: InternshipDocument | null,
|
ipp: InternshipDocument | null,
|
||||||
|
report: Report | null,
|
||||||
}
|
}
|
||||||
|
|
||||||
const INTERNSHIP_MANAGEMENT_INDEX_ENDPOINT = "/management/internship";
|
const INTERNSHIP_MANAGEMENT_INDEX_ENDPOINT = "/management/internship";
|
||||||
const INTERNSHIP_MANAGEMENT_ENDPOINT = "/management/internship/:id";
|
const INTERNSHIP_MANAGEMENT_ENDPOINT = "/management/internship/:id";
|
||||||
const INTERNSHIP_ACCEPT_ENDPOINT = "/management/internship/accept/:id";
|
const INTERNSHIP_ACCEPT_ENDPOINT = "/management/internship/:id/registration/accept";
|
||||||
const INTERNSHIP_REJECT_ENDPOINT = "/management/internship/reject/:id";
|
const INTERNSHIP_REJECT_ENDPOINT = "/management/internship/:id/registration/reject";
|
||||||
|
|
||||||
const internshipInfoDtoTransformer: Transformer<InternshipInfoDTO, InternshipSubmission> = {
|
const internshipInfoDtoTransformer: Transformer<InternshipInfoDTO, InternshipSubmission> = {
|
||||||
transform(subject: InternshipInfoDTO, context?: never): InternshipSubmission {
|
transform(subject: InternshipInfoDTO, context?: never): InternshipSubmission {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const ipp = subject.documentation.find<InternshipDocumentDTO>(doc => doc.type === UploadType.Ipp);
|
const ipp = subject.documentation.find<InternshipDocumentDTO>(doc => doc.type === UploadType.Ipp);
|
||||||
|
const report = subject.report;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
changed: moment(subject.internshipRegistration.submissionDate),
|
changed: moment(subject.internshipRegistration.submissionDate),
|
||||||
@ -50,6 +53,7 @@ const internshipInfoDtoTransformer: Transformer<InternshipInfoDTO, InternshipSub
|
|||||||
state: submissionStateDtoTransformer.transform(subject.internshipRegistration.state),
|
state: submissionStateDtoTransformer.transform(subject.internshipRegistration.state),
|
||||||
type: subject.internshipRegistration.type && internshipTypeDtoTransformer.transform(subject.internshipRegistration.type),
|
type: subject.internshipRegistration.type && internshipTypeDtoTransformer.transform(subject.internshipRegistration.type),
|
||||||
ipp: ipp && internshipDocumentDtoTransformer.transform(ipp),
|
ipp: ipp && internshipDocumentDtoTransformer.transform(ipp),
|
||||||
|
report: report && internshipReportDtoTransformer.transform(report)
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
reverseTransform(subject: InternshipSubmission, context: undefined): InternshipInfoDTO {
|
reverseTransform(subject: InternshipSubmission, context: undefined): InternshipInfoDTO {
|
||||||
|
27
src/management/api/report.ts
Normal file
27
src/management/api/report.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { encapsulate, OneOrMany } from "@/helpers";
|
||||||
|
import { axios } from "@/api";
|
||||||
|
import { prepare } from "@/routing";
|
||||||
|
import { Report } from "@/data/report";
|
||||||
|
|
||||||
|
const REPORT_ACCEPT_ENDPOINT = "/management/report/:id/accept";
|
||||||
|
const REPORT_REJECT_ENDPOINT = "/management/report/:id/reject";
|
||||||
|
|
||||||
|
export async function accept(document: OneOrMany<Report>, comment?: string): Promise<void> {
|
||||||
|
const documents = encapsulate(document)
|
||||||
|
|
||||||
|
await Promise.all(documents.map(document => axios.put(
|
||||||
|
prepare(REPORT_ACCEPT_ENDPOINT, { id: document.id || ""}),
|
||||||
|
JSON.stringify(comment),
|
||||||
|
{ headers: { 'Content-Type': 'application/json' } }
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function discard(document: OneOrMany<Report>, comment: string): Promise<void> {
|
||||||
|
const documents = encapsulate(document)
|
||||||
|
|
||||||
|
await Promise.all(documents.map(document => axios.put(
|
||||||
|
prepare(REPORT_REJECT_ENDPOINT, { id: document.id || ""}),
|
||||||
|
JSON.stringify(comment),
|
||||||
|
{ headers: { 'Content-Type': 'application/json' } }
|
||||||
|
)))
|
||||||
|
}
|
@ -53,7 +53,7 @@ export const EditionManagement = ({ edition }: EditionManagementProps) => {
|
|||||||
<ManagementLink icon={ <FormatPageBreak/> } route={ route("management:edition_ipp_index", { edition: edition.id || "" }) }>
|
<ManagementLink icon={ <FormatPageBreak/> } route={ route("management:edition_ipp_index", { edition: edition.id || "" }) }>
|
||||||
{ t("management:edition.ipp.title") }
|
{ t("management:edition.ipp.title") }
|
||||||
</ManagementLink>
|
</ManagementLink>
|
||||||
<ManagementLink icon={ <FileChartOutline/> } route={ route("management:edition_report_form", { edition: edition.id || "" }) }>
|
<ManagementLink icon={ <FileChartOutline/> } route={ route("management:edition_reports", { edition: edition.id || "" }) }>
|
||||||
{ t("management:edition.reports.title") }
|
{ t("management:edition.reports.title") }
|
||||||
</ManagementLink>
|
</ManagementLink>
|
||||||
<ManagementLink icon={ <CertificateOutline/> } route={ route("management:edition_report_form", { edition: edition.id || "" }) }>
|
<ManagementLink icon={ <CertificateOutline/> } route={ route("management:edition_report_form", { edition: edition.id || "" }) }>
|
||||||
|
141
src/management/edition/report/list.tsx
Normal file
141
src/management/edition/report/list.tsx
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useAsync, useAsyncState } from "@/hooks";
|
||||||
|
import { useSpacing } from "@/styles";
|
||||||
|
import api from "@/management/api";
|
||||||
|
import { Box, Button, Container, IconButton, Typography } from "@material-ui/core";
|
||||||
|
import MaterialTable, { Column } from "material-table";
|
||||||
|
import { actionsColumn } from "@/management/common/helpers";
|
||||||
|
import { FileDownloadOutline, FileFind, Refresh, StickerCheckOutline, StickerRemoveOutline } from "mdi-material-ui";
|
||||||
|
import { Page } from "@/pages/base";
|
||||||
|
import { Actions } from "@/components";
|
||||||
|
import { BulkActions } from "@/management/common/BulkActions";
|
||||||
|
import { Async } from "@/components/async";
|
||||||
|
import { MaterialTableTitle } from "@/management/common/MaterialTableTitle";
|
||||||
|
import { EditionManagement, EditionManagementProps } from "@/management/edition/manage";
|
||||||
|
import { Link as RouterLink } from "react-router-dom";
|
||||||
|
import { route } from "@/routing";
|
||||||
|
import { AcceptSubmissionDialog, DiscardSubmissionDialog } from "@/components/acceptance-action";
|
||||||
|
import { ProposalPreview } from "@/components/proposalPreview";
|
||||||
|
import { InternshipSubmission } from "@/management/api/internship";
|
||||||
|
import { StateLabel } from "@/management/edition/internship/common";
|
||||||
|
import { createPortal } from "react-dom";
|
||||||
|
import { Internship, Stateful } from "@/data";
|
||||||
|
import { FileInfo } from "@/components/fileinfo";
|
||||||
|
import { Alert } from "@material-ui/lab";
|
||||||
|
import { InternshipDocument } from "@/api/dto/internship-registration";
|
||||||
|
import { Report } from "@/data/report";
|
||||||
|
|
||||||
|
const title = "edition.reports.title";
|
||||||
|
|
||||||
|
export const canAccept = (subject: Stateful | null) => !!(subject && ["declined", "awaiting"].includes(subject.state));
|
||||||
|
export const canDiscard = (subject: Stateful | null) => !!(subject && ["accepted", "awaiting"].includes(subject.state));
|
||||||
|
|
||||||
|
export const ReportManagement = ({ edition }: EditionManagementProps) => {
|
||||||
|
const { t } = useTranslation("management");
|
||||||
|
const [result, setInternshipsPromise] = useAsyncState<InternshipSubmission[]>();
|
||||||
|
const [selected, setSelected] = useState<InternshipSubmission[]>([]);
|
||||||
|
const spacing = useSpacing(2);
|
||||||
|
|
||||||
|
const updateInternshipList = () => {
|
||||||
|
setInternshipsPromise(api.internship.all(edition));
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(updateInternshipList, []);
|
||||||
|
|
||||||
|
const AcceptAction = ({ internship }: { internship: InternshipSubmission }) => {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
const handleSubmissionAccept = async (comment?: string) => {
|
||||||
|
setOpen(false);
|
||||||
|
await api.report.accept(internship.report as Report, comment);
|
||||||
|
updateInternshipList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<IconButton onClick={ () => setOpen(true) }><StickerCheckOutline /></IconButton>
|
||||||
|
{ createPortal(
|
||||||
|
<AcceptSubmissionDialog onAccept={ handleSubmissionAccept } label="plan" open={ open } onClose={ () => setOpen(false) }/>,
|
||||||
|
document.getElementById("modals") as Element,
|
||||||
|
) }
|
||||||
|
</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DiscardAction = ({ internship }: { internship: InternshipSubmission }) => {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
const handleSubmissionDiscard = async (comment: string) => {
|
||||||
|
setOpen(false);
|
||||||
|
await api.report.discard(internship.report as Report, comment);
|
||||||
|
updateInternshipList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<IconButton onClick={ () => setOpen(true) }><StickerRemoveOutline /></IconButton>
|
||||||
|
{ createPortal(
|
||||||
|
<DiscardSubmissionDialog onDiscard={ handleSubmissionDiscard } label="plan" open={ open } onClose={ () => setOpen(false) }/>,
|
||||||
|
document.getElementById("modals") as Element,
|
||||||
|
) }
|
||||||
|
</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InternshipDetails = ({ summary }: { summary: InternshipSubmission }) => {
|
||||||
|
return <Box m={ 3 }>
|
||||||
|
{ summary.report && JSON.stringify(summary.report) }
|
||||||
|
</Box>
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns: Column<InternshipSubmission>[] = [
|
||||||
|
{
|
||||||
|
title: t("internship.column.student"),
|
||||||
|
render: internship => <>{internship.intern?.name} {internship.intern?.surname}</>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("internship.column.album"),
|
||||||
|
field: "intern.albumNumber",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("internship.column.type"),
|
||||||
|
field: "type.label.pl",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("internship.column.changed"),
|
||||||
|
render: summary => summary.changed?.format("yyyy-MM-DD")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("internship.column.status"),
|
||||||
|
render: summary => <StateLabel state={ summary.report?.state || null } />
|
||||||
|
},
|
||||||
|
actionsColumn(internship => <>
|
||||||
|
{ canAccept(internship.report) && <AcceptAction internship={ internship } /> }
|
||||||
|
{ canDiscard(internship.report) && <DiscardAction internship={ internship } /> }
|
||||||
|
</>)
|
||||||
|
];
|
||||||
|
|
||||||
|
return <Page>
|
||||||
|
<Page.Header maxWidth="lg">
|
||||||
|
<EditionManagement.Breadcrumbs>
|
||||||
|
<Typography color="textPrimary">{ t(title) }</Typography>
|
||||||
|
</EditionManagement.Breadcrumbs>
|
||||||
|
<Page.Title>{ t(title) }</Page.Title>
|
||||||
|
</Page.Header>
|
||||||
|
<Container maxWidth="lg" className={ spacing.vertical }>
|
||||||
|
<Actions>
|
||||||
|
<Button onClick={ updateInternshipList } startIcon={ <Refresh /> }>{ t("refresh") }</Button>
|
||||||
|
</Actions>
|
||||||
|
{ selected.length > 0 && <BulkActions>
|
||||||
|
|
||||||
|
</BulkActions> }
|
||||||
|
<Async async={ result } keepValue>{
|
||||||
|
internships => <MaterialTable
|
||||||
|
title={ <MaterialTableTitle result={ result } label={ t(title) }/> }
|
||||||
|
columns={ columns }
|
||||||
|
data={ internships }
|
||||||
|
onSelectionChange={ internships => setSelected(internships) }
|
||||||
|
options={ { selection: true, pageSize: 10 } }
|
||||||
|
detailPanel={ summary => <InternshipDetails summary={ summary } /> }
|
||||||
|
/>
|
||||||
|
}</Async>
|
||||||
|
</Container>
|
||||||
|
</Page>
|
||||||
|
}
|
@ -11,6 +11,7 @@ import { InternshipManagement } from "@/management/edition/internship/list";
|
|||||||
import { InternshipDetails } from "@/management/edition/internship/details";
|
import { InternshipDetails } from "@/management/edition/internship/details";
|
||||||
import { PlanManagement } from "@/management/edition/ipp/list";
|
import { PlanManagement } from "@/management/edition/ipp/list";
|
||||||
import { ReportFields } from "@/management/report/fields/list";
|
import { ReportFields } from "@/management/report/fields/list";
|
||||||
|
import { ReportManagement } from "@/management/edition/report/list";
|
||||||
|
|
||||||
export const managementRoutes: Route[] = ([
|
export const managementRoutes: Route[] = ([
|
||||||
{ name: "index", path: "/", content: ManagementIndex, exact: true },
|
{ name: "index", path: "/", content: ManagementIndex, exact: true },
|
||||||
@ -20,6 +21,7 @@ export const managementRoutes: Route[] = ([
|
|||||||
{ name: "edition_manage", path: "/editions/:edition", content: EditionManagement, tags: ["edition"], exact: true },
|
{ name: "edition_manage", path: "/editions/:edition", content: EditionManagement, tags: ["edition"], exact: true },
|
||||||
{ name: "edition_internship", path: "/editions/:edition/internships/:internship", content: InternshipDetails, tags: ["edition"] },
|
{ name: "edition_internship", path: "/editions/:edition/internships/:internship", content: InternshipDetails, tags: ["edition"] },
|
||||||
{ name: "edition_internships", path: "/editions/:edition/internships", content: InternshipManagement, tags: ["edition"] },
|
{ name: "edition_internships", path: "/editions/:edition/internships", content: InternshipManagement, tags: ["edition"] },
|
||||||
|
{ name: "edition_reports", path: "/editions/:edition/reports", content: ReportManagement, tags: ["edition"] },
|
||||||
{ name: "edition_ipp_index", path: "/editions/:edition/ipp", content: PlanManagement, tags: ["edition"] },
|
{ name: "edition_ipp_index", path: "/editions/:edition/ipp", content: PlanManagement, tags: ["edition"] },
|
||||||
{ name: "editions", path: "/editions", content: EditionsManagement },
|
{ name: "editions", path: "/editions", content: EditionsManagement },
|
||||||
|
|
||||||
|
@ -2,16 +2,37 @@ import { useSelector } from "react-redux";
|
|||||||
import { AppState } from "@/state/reducer";
|
import { AppState } from "@/state/reducer";
|
||||||
import { getSubmissionStatus, SubmissionState, SubmissionStatus } from "@/state/reducer/submission";
|
import { getSubmissionStatus, SubmissionState, SubmissionStatus } from "@/state/reducer/submission";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Box, Button, ButtonProps, StepProps } from "@material-ui/core";
|
import { Box, Button, ButtonProps, Dialog, DialogContent, DialogProps, DialogTitle, StepProps, Typography } from "@material-ui/core";
|
||||||
import { FileUploadOutline } from "mdi-material-ui/index";
|
import { FileFind, FileUploadOutline } from "mdi-material-ui/index";
|
||||||
import { route } from "@/routing";
|
import { route } from "@/routing";
|
||||||
import { Link as RouterLink } from "react-router-dom";
|
import { Link as RouterLink } from "react-router-dom";
|
||||||
import { Actions, Step } from "@/components";
|
import { Actions, Step } from "@/components";
|
||||||
import React, { HTMLProps } from "react";
|
import React, { HTMLProps, useState } from "react";
|
||||||
import { Alert, AlertTitle } from "@material-ui/lab";
|
import { Alert, AlertTitle } from "@material-ui/lab";
|
||||||
import { ContactButton, Status } from "@/pages/steps/common";
|
import { ContactButton, Status } from "@/pages/steps/common";
|
||||||
import { useCurrentEdition, useDeadlines } from "@/hooks";
|
import { useCurrentEdition, useDeadlines } from "@/hooks";
|
||||||
import { useSpacing } from "@/styles";
|
import { useSpacing } from "@/styles";
|
||||||
|
import { Report } from "@/data/report";
|
||||||
|
import { sampleReportSchema } from "@/provider/dummy/report";
|
||||||
|
import { createPortal } from "react-dom";
|
||||||
|
import { getInternshipReport } from "@/state/reducer/report";
|
||||||
|
|
||||||
|
export type ReportPreviewDialogProps = {
|
||||||
|
report: Report;
|
||||||
|
} & DialogProps;
|
||||||
|
|
||||||
|
export const ReportPreviewDialog = ({ report, ...props }: ReportPreviewDialogProps) => {
|
||||||
|
const schema = sampleReportSchema;
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return <Dialog { ...props } maxWidth="md">
|
||||||
|
<DialogTitle>{ t("steps.report.preview") }</DialogTitle>
|
||||||
|
<DialogContent>{ schema.map(field => <>
|
||||||
|
<Typography variant="subtitle2">{ field.label.pl }</Typography>
|
||||||
|
{ JSON.stringify(report.fields[`field_${field.id}`]) }
|
||||||
|
</> )}</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
}
|
||||||
|
|
||||||
const ReportActions = () => {
|
const ReportActions = () => {
|
||||||
const status = useSelector<AppState, SubmissionStatus>(state => getSubmissionStatus(state.report));
|
const status = useSelector<AppState, SubmissionStatus>(state => getSubmissionStatus(state.report));
|
||||||
@ -23,9 +44,27 @@ const ReportActions = () => {
|
|||||||
{ children }
|
{ children }
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
const ReviewAction = (props: ButtonProps) => {
|
||||||
|
const [open, setOpen,] = useState<boolean>(false);
|
||||||
|
const report = useSelector<AppState, Report>(state => getInternshipReport(state.report) as Report);
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<Button startIcon={ <FileFind/> }
|
||||||
|
onClick={ () => setOpen(true) }
|
||||||
|
{ ...props as any }>
|
||||||
|
{ t('review') }
|
||||||
|
</Button>
|
||||||
|
{ createPortal(
|
||||||
|
<ReportPreviewDialog report={ report } open={ open } onClose={ () => setOpen(false) }/>,
|
||||||
|
document.getElementById("modals") as Element,
|
||||||
|
) }
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case "awaiting":
|
case "awaiting":
|
||||||
return <Actions>
|
return <Actions>
|
||||||
|
<ReviewAction />
|
||||||
</Actions>
|
</Actions>
|
||||||
case "accepted":
|
case "accepted":
|
||||||
return <Actions>
|
return <Actions>
|
||||||
|
@ -28,6 +28,8 @@ edition:
|
|||||||
title: Indywidualne Plany Praktyk
|
title: Indywidualne Plany Praktyk
|
||||||
index:
|
index:
|
||||||
title: "Edycje praktyk"
|
title: "Edycje praktyk"
|
||||||
|
reports:
|
||||||
|
title: "Raporty praktyki"
|
||||||
field:
|
field:
|
||||||
id: Identyfikator
|
id: Identyfikator
|
||||||
start: Początek
|
start: Początek
|
||||||
|
Loading…
Reference in New Issue
Block a user