diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts
index 1afafe7c..2512de6b 100644
--- a/src/locales/en-US.ts
+++ b/src/locales/en-US.ts
@@ -160,6 +160,8 @@ export default {
access: 'Access',
answers: 'Answers',
answer: 'Answer',
+ webinars: "Webinars",
+ 'webinars.screenSaves': 'Screen saves',
'menu.Webinars': 'Webinars',
'menu.NewWebinar': 'New webinar',
'menu.Courses': 'Courses',
diff --git a/src/locales/pl-PL.ts b/src/locales/pl-PL.ts
index a3e450b2..190d2a8d 100644
--- a/src/locales/pl-PL.ts
+++ b/src/locales/pl-PL.ts
@@ -167,7 +167,12 @@ export default {
'menu.Other activities.StationaryEvents': 'Wydarzenia stacjonarne',
'menu.Other activities.Questionnaire Form': 'Ankiety',
'menu.Other activities.Dictionary': 'Słownik',
+ 'menu.Other activities.Word': 'Słowo',
'stationary_event.edit': 'Formularz Wydarzenia stacjonarne',
+ 'menu.My Profile': 'Mój profil',
+ 'menu.My Profile.My Profile': 'Mój profil',
+ Webinars: "Webinary",
+ 'webinars.screenSaves': 'Zapis Ekranu',
stationary_event: 'Wydarzenie stacjonarne',
'menu.reset': 'reset',
finished_at: 'Data zakończenia',
@@ -235,6 +240,7 @@ export default {
recording_will_be_deleted: 'Po tym czasie zostanie ono skasowane',
engagement_rating: 'Ocena zaangażowania',
ai_analysis_average: 'Średni wynik analizy AI dla całego nagrania {modelType}.',
+ ai_warn_video_buffer: "Video nagrania jest obecnie przetwarzane, zdjęcia podglądu nagrania na wykresie w poszczególnych przedziałach czasowych mogą być obecnie niedostępne. Spróbuj ponowanie za kilka minut.",
consultationFragment: "konsultacji",
webinarFragment: "webinaru",
resolution: 'Rozdzielczość danych',
diff --git a/src/pages/Consultations/components/EffectivenessAnalysis.tsx b/src/pages/Consultations/components/EffectivenessAnalysis.tsx
index c2c80dab..e7692465 100644
--- a/src/pages/Consultations/components/EffectivenessAnalysis.tsx
+++ b/src/pages/Consultations/components/EffectivenessAnalysis.tsx
@@ -262,7 +262,7 @@ export const EffectivenessAnalysis = ({
page: current,
date_from,
date_to,
- ...createTableOrderObject(sort, 'term'),
+ ...createTableOrderObject(sort, 'id'),
});
setLoading(false);
@@ -282,10 +282,6 @@ export const EffectivenessAnalysis = ({
}
}}
columns={columns}
- pagination={{
- pageSize: 10,
- showSizeChanger: true,
- }}
/>
);
};
diff --git a/src/pages/Consultations/components/EffectivenessAnalysisDetails.tsx b/src/pages/Consultations/components/EffectivenessAnalysisDetails.tsx
index b1817f65..4345e7cc 100644
--- a/src/pages/Consultations/components/EffectivenessAnalysisDetails.tsx
+++ b/src/pages/Consultations/components/EffectivenessAnalysisDetails.tsx
@@ -7,7 +7,7 @@ import type {
} from '@/pages/Consultations/components/types';
import { getAnalyticsChartFrames, getModelAnalytics } from '@/services/escola-lms/consultations';
import {
- ANALYSIS_COLORS, EmotionKey, formatRating, getLabelColorByValue,
+ ANALYSIS_COLORS, EmotionKey, formatRating,
getRatingLabelColorByValue
} from '@/utils/utils';
import { PageContainer } from '@ant-design/pro-components';
@@ -15,12 +15,15 @@ import { Card, Col, Select, Space, Typography, message } from 'antd';
import React, { useEffect, useMemo, useState } from 'react';
import styled from 'styled-components';
import { FormattedMessage, Link, useParams, useSelectedRoutes } from 'umi';
+import {WarningOutlined} from "@ant-design/icons";
const { Text } = Typography;
const PageWrapper = styled.div`
padding: 0;
min-height: 100vh;
+ background: ${ANALYSIS_COLORS.bgLight};
+ border-radius: 10px;
`;
const StyledCard = styled(Card)`
@@ -65,6 +68,20 @@ const SectionTitle = styled(Text)`
font-size: 16px;
`;
+const VideoScreenWarning = styled.div`
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 10px;
+ color: ${ANALYSIS_COLORS.orange};
+`;
+
+const VideoScreenWarningText = styled(Text)`
+ margin: 0;
+ color: ${ANALYSIS_COLORS.orange};
+`;
+
+
const TIME_OPTIONS = [
{ value: 15, label: },
{ value: 30, label: },
@@ -79,17 +96,11 @@ const EffectivenessAnalysisDetails = () => {
const [analysisMeta, setAnalysisMeta] = useState(null);
const [chartData, setChartData] = useState([]);
const routes = useSelectedRoutes();
- const color = useMemo(
- () => getLabelColorByValue(analysisMeta?.rating ? analysisMeta.rating : 0),
- [analysisMeta?.rating],
- );
const ratingColor = useMemo(
() => getRatingLabelColorByValue(analysisMeta?.rating ? analysisMeta.rating : 0),
[analysisMeta?.rating],
);
- console.log(color, 'color');
-
const modelType = useMemo(() => {
const currentRoute = routes[routes.length - 1]?.route as any;
return currentRoute?.modelType;
@@ -220,7 +231,14 @@ const EffectivenessAnalysisDetails = () => {
-
+ {analysisMeta?.processing_video && (
+
+
+
+
+
+
+ )}
{chartData && (
[] = [
- {
- title: ,
- dataIndex: 'consultation_term_id',
- hideInSearch: true,
- sorter: true,
- width: '80px',
- },
- {
- title: ,
- dataIndex: 'user',
- render: (_, item) => `${item.user?.first_name} ${item.user?.last_name} ${item.user?.email}`,
- sorter: true,
- },
- {
- title: ,
- dataIndex: 'date',
- sorter: true,
- render: (_, item) => moment(item.date).format('YYYY-MM-DD HH:mm'),
- },
- {
- title: ,
- dataIndex: 'status',
- sorter: true,
- render: (_, item) => (
- }
- />
- ),
- },
-];
+interface Props {
+ consultation?: number;
+ webinar?: number;
+ webinarTimestamp?: number;
+}
-const ScreenSaves: React.FC<{ consultation: number }> = ({ consultation }) => {
+const ScreenSaves: React.FC = ({ consultation, webinar, webinarTimestamp }) => {
const [loading, setLoading] = useState(false);
const [appointments, setAppointments] = useState([]);
+ const [webinarUsers, setWebinarUsers] = useState([]);
const intl = useIntl();
+ const resourceId = consultation || webinar;
+
+ const consultationColumns = useMemo(
+ (): ProColumns[] => [
+ {
+ title: ,
+ dataIndex: 'consultation_term_id',
+ hideInSearch: true,
+ sorter: true,
+ width: 80,
+ },
+ {
+ title: ,
+ dataIndex: 'user',
+ sorter: true,
+ render: (_, item) =>
+ `${item.user?.first_name ?? ''} ${item.user?.last_name ?? ''} ${item.user?.email ?? ''}`,
+ },
+ {
+ title: ,
+ dataIndex: 'date',
+ sorter: true,
+ render: (_, item) => moment(item.date).format('YYYY-MM-DD HH:mm'),
+ },
+ {
+ title: ,
+ dataIndex: 'status',
+ sorter: true,
+ render: (_, item) => (
+ }
+ />
+ ),
+ },
+ {
+ title: 'Analiza obrazu',
+ dataIndex: 'files',
+ render: (_, item) => (
+
+ ),
+ },
+ ],
+ [resourceId],
+ );
+
+ const webinarColumns = useMemo(
+ (): ProColumns[] => [
+ {
+ title: ,
+ dataIndex: 'id',
+ hideInSearch: true,
+ sorter: true,
+ width: 80,
+ },
+ {
+ title: ,
+ dataIndex: 'user',
+ sorter: true,
+ render: (_, item) =>
+ `${item.first_name ?? ''} ${item.last_name ?? ''} ${item.email ?? ''}`,
+ },
+ {
+ title: ,
+ dataIndex: 'active_to',
+ render: () =>
+ webinarTimestamp
+ ? moment.unix(webinarTimestamp).format('YYYY-MM-DD HH:mm')
+ : '-',
+ },
+ {
+ title: 'Analiza obrazu',
+ dataIndex: 'files',
+ render: (_, item) => (
+
+ ),
+ },
+ ],
+ [resourceId],
+ );
+
+ const fetchData = useCallback(() => {
+ if (!resourceId) return;
- const fetchAppointments = useCallback(() => {
setLoading(true);
- getSchedule(consultation)
+
+ const promise = consultation
+ ? getConsultationSchedule(consultation)
+ : getWebinarUsers(webinar as number);
+
+ promise
.then((response) => {
- if (response.success) {
- setAppointments(response.data);
+ if (!response?.success) return;
+ if (consultation) {
+ setAppointments(response.data as API.ConsultationAppointment[]);
+ } else {
+ setWebinarUsers(response.data as API.UserItem[]);
}
})
.catch(() => {
message.error();
})
.finally(() => setLoading(false));
- }, [consultation]);
+ }, [consultation, webinar, resourceId]);
useEffect(() => {
- fetchAppointments();
- }, [consultation]);
-
- return (
-
- {loading ? (
-
- ) : (
-
- headerTitle={intl.formatMessage({
- id: 'Consultations',
- defaultMessage: 'Consultations',
- })}
- loading={loading}
- rowKey="consultation_term_id"
- search={false}
- request={async ({}, sort) => {
- const sortArr = sort && Object.entries(sort)[0];
- let newArray = appointments.filter((item) => item.status === 'approved');
-
- if (sortArr) {
- newArray = sortArrayByKey(
- newArray,
- sortArr[0],
- sortArr[1] === 'ascend' ? false : true,
- );
- }
- return {
- data: newArray,
- total: newArray.length,
- success: true,
- };
- }}
- columns={[
- ...TableColumns,
-
- {
- title: 'Analiza obrazu',
- dataIndex: 'status',
- sorter: true,
- render: (_, item) => (
-
-
-
- ),
- },
- ]}
- />
- )}
-
- );
+ fetchData();
+ }, [fetchData]);
+
+ if (loading) {
+ return ;
+ }
+
+ if (consultation) {
+ return (
+
+ headerTitle={intl.formatMessage({
+ id: 'Consultations',
+ defaultMessage: 'Consultations',
+ })}
+ loading={loading}
+ rowKey="consultation_term_id"
+ search={false}
+ options={{
+ reload: false,
+ }}
+ dataSource={appointments}
+ request={async (_params, sort) => {
+ const sortArr = sort && Object.entries(sort)[0];
+ let filteredData = appointments.filter((item) => item.status === 'approved');
+
+ if (sortArr) {
+ filteredData = sortArrayByKey(
+ filteredData,
+ sortArr[0],
+ sortArr[1] !== 'ascend',
+ );
+ }
+ return {
+ data: filteredData,
+ total: filteredData.length,
+ success: true,
+ };
+ }}
+ columns={consultationColumns}
+ />
+ );
+ }
+
+ if (webinar) {
+ return (
+
+ headerTitle={intl.formatMessage({
+ id: 'Webinars',
+ defaultMessage: 'Webinars',
+ })}
+ loading={loading}
+ rowKey="id"
+ search={false}
+ options={{
+ reload: false,
+ }}
+ dataSource={webinarUsers}
+ request={async (_params, sort) => {
+ const sortArr = sort && Object.entries(sort)[0];
+ let filteredData = [...webinarUsers];
+
+ if (sortArr) {
+ filteredData = sortArrayByKey(
+ filteredData,
+ sortArr[0],
+ sortArr[1] !== 'ascend',
+ );
+ }
+ return {
+ data: filteredData,
+ total: filteredData.length,
+ success: true,
+ };
+ }}
+ columns={webinarColumns}
+ />
+ );
+ }
+
+ return null;
};
export default ScreenSaves;
diff --git a/src/pages/Consultations/components/types.ts b/src/pages/Consultations/components/types.ts
index f4997378..4e52e500 100644
--- a/src/pages/Consultations/components/types.ts
+++ b/src/pages/Consultations/components/types.ts
@@ -4,6 +4,7 @@ export interface AnalysisMeta {
rating: number;
url: string | null;
url_expiration_time_millis: number | null;
+ processing_video?: boolean;
}
export interface AnalysisData {
diff --git a/src/pages/Webinars/form.tsx b/src/pages/Webinars/form.tsx
index 2d6501f2..b44601bb 100644
--- a/src/pages/Webinars/form.tsx
+++ b/src/pages/Webinars/form.tsx
@@ -20,6 +20,9 @@ import { PageContainer } from '@ant-design/pro-layout';
import { Alert, Button, Col, Row, Spin, message } from 'antd';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { FormattedMessage, history, useIntl, useParams } from 'umi';
+import ScreenSaves from "@/pages/Consultations/components/ScreenSaves";
+import {settings} from "@/services/escola-lms/settings";
+import moment from "moment";
enum TabNames {
ATTRIBUTES = 'attributes',
@@ -28,6 +31,7 @@ enum TabNames {
TAGS = 'tags',
BRANDING = 'branding',
USER_SUBMISSION = 'user_submission',
+ SCREENSAVES = 'screensaves',
}
const WebinarForm = () => {
@@ -37,10 +41,15 @@ const WebinarForm = () => {
const isNew = webinar === 'new';
const [data, setData] = useState>();
const { manageCourseEdit, setManageCourseEdit, validateCourseEdit } = useValidateFormEdit();
-
+ const [showScreenSaves, setShowScreenSaves] = useState(false);
const [form] = ProForm.useForm();
const fetchData = useCallback(async () => {
+ const config = await settings({ per_page: -1 });
+
+ if ('data' in config) {
+ setShowScreenSaves(config.data.find((c) => c.key === 'show_screen_saves')?.value === '1');
+ }
const response = await getWebinar(Number(webinar));
if (response.success) {
if (tab === TabNames.ATTRIBUTES) {
@@ -445,6 +454,14 @@ const WebinarForm = () => {
{webinar && }
)}
+ {!isNew && showScreenSaves && (
+ }
+ >
+
+
+ )}
{/* CONFIRM MODAL COMPONENT */}
>(
+ `/api/admin/webinars/${webinarId}/users`,
+ {
+ method: 'GET',
+ ...(options || {}),
+ },
+ );
+}