fixed some bugs and changed inputs on converters

main
alex 2024-09-15 13:19:03 +02:00
parent c40cba88d4
commit 73d5804f8c
20 changed files with 168 additions and 90 deletions

View File

@ -154,10 +154,17 @@
},
"lessonPage": {
"finishLessonButton": "Lektion beenden",
"questions": "Fragen"
"questions": "Fragen",
"addContentButton": "Inhalt hinzufügen"
},
"lessonPageEditor": {
"previewParagraph": "Vorschau der Lektion",
"pageContentParagraph": "Seiteninhalt der Lektion",
"titlePlaceholder": "Titel hier eingeben..."
},
"lessonQuestions": {
"messageQuestionSuccessfullyCreated": "Frage erfolgreich erstellt",
"messageReplySuccessfullyCreated": "Antwort erfolgreich erstellt",
"askAQuestion": "Frage stellen",
"typeSomething": "Etwas schreiben...",
"submitButton": "Absenden",
@ -184,6 +191,7 @@
}
},
"lessonComponentsConverter": {
"titlePlaceholder": "Titel hier eingeben...",
"textPlaceholder": "Text hier eingeben...",
"noImageProvided": "Kein Bild bereitgestellt",
"gallery": "Galerie",

View File

@ -154,10 +154,17 @@
},
"lessonPage": {
"finishLessonButton": "Finish lesson",
"questions": "Questions"
"questions": "Questions",
"addContentButton": "Add Content"
},
"lessonPageEditor": {
"previewParagraph": "Preview of the lesson",
"pageContentParagraph": "Page content of the lesson",
"titlePlaceholder": "Input title here..."
},
"lessonQuestions": {
"messageQuestionSuccessfullyCreated": "Question successfully created",
"messageReplySuccessfullyCreated": "Reply successfully created",
"askAQuestion": "Ask a question",
"typeSomething": "Type something...",
"submitButton": "Submit",
@ -184,6 +191,7 @@
}
},
"lessonComponentsConverter": {
"titlePlaceholder": "Input title here...",
"textPlaceholder": "Input text here...",
"noImageProvided": "No image provided",
"gallery": "Gallery",

View File

@ -1,16 +1,16 @@
import { Route, Routes } from "react-router-dom";
import { MySupsenseFallback } from "../../../shared/components/MySupsenseFallback";
import { MySupsenseFallback } from "shared/components/MySupsenseFallback";
import { Constants } from "../../utils/utils";
import Team from "../../../features/Team";
import Roles from "../../../features/Roles";
import WhatsNew from "../../../features/WhatsNew";
import SuggestFeature from "../../../features/SuggestFeature";
import ContactSupport from "../../../features/ContactSupport";
import Lessons from "../../../features/Lessons";
import Settings from "../../../features/Settings";
import PageNotFound from "../../../features/PageNotFound";
import LessonPage from "../../../features/Lessons/LessonPage";
import LessonPageEditor from "../../../features/Lessons/LessonPageEditor";
import Team from "features/Team";
import Roles from "features/Roles";
import WhatsNew from "features/WhatsNew";
import SuggestFeature from "features/SuggestFeature";
import ContactSupport from "features/ContactSupport";
import Lessons from "features/Lessons";
import Settings from "features/Settings";
import PageNotFound from "features/PageNotFound";
import LessonPage from "features/Lessons/LessonPage";
import LessonPageEditor from "features/Lessons/LessonPageEditor";
import TeamCreateUser from "features/Team/CreateUser";
import Board from "features/Board";
import UserProfile from "features/UserProfile";

View File

@ -6,7 +6,7 @@ import { SideMenuContent, SideMenuEditorContent } from "../SideMenu";
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { setIsSideMenuCollapsed } from "../SideMenu/sideMenuSlice";
import { editorActive } from "../../../features/Lessons/LessonPageEditor/lessonPageEditorSlice";
import { editorActive } from "features/Lessons/LessonPageEditor/lessonPageEditorSlice";
import MyDndContext from "./MyDndContext";
import AiChat from "features/AiChat";

View File

@ -55,7 +55,7 @@ export default function HeaderBar(props: HeaderBarProps = { theme: "light" }) {
zIndex: 999,
}}
>
<Flex align="center" gap={16}>
<Flex align="center">
<div
className={isDarkMode ? styles.containerDark : styles.containerLight}
style={{ borderRadius: 28, padding: 4 }}

View File

@ -3,9 +3,16 @@ import AppRoutes from "../AppRoutes";
import { useSelector } from "react-redux";
import { isSideMenuCollapsed } from "../SideMenu/sideMenuSlice";
import { BreakpointLgWidth } from "../../utils/utils";
import { useLocation } from "react-router-dom";
import { useEffect } from "react";
export default function PageContent() {
const isCollpased = useSelector(isSideMenuCollapsed);
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return (
<Layout

View File

@ -218,7 +218,7 @@ export function SideMenuContent() {
}}
></div>
<div>
<div style={{ overflowY: "auto" }}>
<Flex justify="center" style={{ paddingBottom: 24, width: "100%" }}>
{appLogoUrl !== null && (
<img

View File

@ -1,14 +1,10 @@
import { Button, Card, ConfigProvider, Flex, Form, Input } from "antd";
import { useForm } from "antd/es/form/Form";
import styles from "./styles.module.css";
import {
Constants,
EncodeStringToBase64,
myFetch,
} from "../../../core/utils/utils";
import { Constants, EncodeStringToBase64, myFetch } from "core/utils/utils";
import { useState } from "react";
import { useDispatch } from "react-redux";
import { setUserAuthenticated } from "../../../core/reducers/appSlice";
import { setUserAuthenticated } from "core/reducers/appSlice";
type FieldType = {
email: string;

View File

@ -1,5 +1,5 @@
import { Button, Flex } from "antd";
import { CheckOutlined } from "@ant-design/icons";
import { CheckOutlined, PlusOutlined } from "@ant-design/icons";
import HeaderBar from "core/components/Header";
import { useLocation, useNavigate, useParams } from "react-router-dom";
import { Constants } from "core/utils/utils";
@ -24,8 +24,10 @@ import MyCenteredSpin from "shared/components/MyCenteredSpin";
import { useTranslation } from "react-i18next";
const LessonContents: React.FC = () => {
const { t } = useTranslation();
const dispatch = useDispatch();
const { lessonId } = useParams();
const navigate = useNavigate();
const lessonContents = useSelector(lessonPageContents);
@ -52,7 +54,22 @@ const LessonContents: React.FC = () => {
if (isLoading) return <MyCenteredSpin height="140px" />;
if (error) return <MyErrorResult />;
if (!lessonContents || lessonContents.length === 0) return <MyEmpty />;
if (!lessonContents || lessonContents.length === 0)
return (
<MyEmpty style={{ paddingBottom: 64 }}>
<Button
type="primary"
icon={<PlusOutlined />}
onClick={() =>
navigate(
`${Constants.ROUTE_PATHS.LESSIONS.ROOT}/${lessonId}/editor`
)
}
>
{t("lessonPage.addContentButton")}
</Button>
</MyEmpty>
);
return (
<>

View File

@ -79,8 +79,6 @@ const SortableEditorItem = (props: { item: LessonContent }) => {
mode="edititable"
lessonContent={lnContent}
onEdit={(data) => {
console.log("edit", lnContent.Id, data);
dispatch(
updateLessonContent({
id: lnContent.Id,

View File

@ -9,9 +9,9 @@ import {
setLessonThumbnailUrl,
setPageEditorLessonState,
} from "./lessonPageEditorSlice";
import { useEffect } from "react";
import { useEffect, useRef } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Card, Flex } from "antd";
import { Card, Flex, Typography } from "antd";
import { Constants } from "core/utils/utils";
import HeaderBar from "core/components/Header";
import Droppable from "./Droppable";
@ -28,10 +28,12 @@ import {
addWebSocketReconnectListener,
removeWebSocketReconnectListener,
} from "core/services/websocketService";
import { useTranslation } from "react-i18next";
const PreviewCard: React.FC = () => {
const dispatch = useDispatch();
const { lessonId } = useParams();
const debounceRef = useRef<null | NodeJS.Timeout>(null);
const dataLessonThumbnail = useSelector(lessonThumbnail);
@ -69,17 +71,27 @@ const PreviewCard: React.FC = () => {
Title: dataLessonThumbnail.title || "",
ThumbnailUrl: dataLessonThumbnail.url || "",
}}
onEditTitle={async (newTitle) => {
onEditTitle={(newTitle) => {
try {
await updateLessonPreviewTitle({
if (debounceRef.current) {
clearTimeout(debounceRef.current);
}
debounceRef.current = setTimeout(() => {
try {
updateLessonPreviewTitle({
lessonId: lessonId as string,
newTitle: newTitle,
}).unwrap();
});
dispatch(setLessonThumbnailTitle(newTitle));
} catch (err) {
console.error(err);
}
}, 3000);
} catch (err) {
console.error(err);
}
}}
/>
);
@ -126,6 +138,7 @@ const LessonContentComponents: React.FC = () => {
};
export default function LessonPageEditor() {
const { t } = useTranslation();
const { lessonId } = useParams();
const navigate = useNavigate();
@ -159,15 +172,19 @@ export default function LessonPageEditor() {
sticky
/>
<Flex justify="center" style={{ paddingTop: 24 }}>
<Flex
justify="center"
vertical
gap={16}
className={styles.cardContainer}
>
<Flex justify="center" style={{ padding: 12 }}>
<Flex justify="center" vertical className={styles.cardContainer}>
<Typography.Paragraph type="secondary" style={{ margin: 0 }}>
{t("lessonPageEditor.previewParagraph")}
</Typography.Paragraph>
<PreviewCard />
<Typography.Paragraph
type="secondary"
style={{ margin: 0, paddingTop: 16 }}
>
{t("lessonPageEditor.pageContentParagraph")}
</Typography.Paragraph>
<LessonContentComponents />
</Flex>
</Flex>

View File

@ -12,7 +12,7 @@ export const lessonPageEditorSlice = createSlice({
editorActive: false,
currentLessonId: "", // required in sideMenu because has no access to useParams
lessonThumbnail: {
title: "Test",
title: "",
url: "",
},
lessonContents: [] as LessonContent[],

View File

@ -291,18 +291,19 @@ export function QuestionUIRaw({
return (
<>
<Flex gap={16}>
<div style={{ marginTop: 4 }}>
<MyUserAvatar
profilePictureUrl={user.ProfilePictureUrl}
firstName={user.FirstName}
disableCursorPointer
size={42}
/>
</div>
<Flex vertical style={{ width: "100%" }}>
<Typography style={{ fontSize: 24, fontWeight: 800 }}>
<Typography.Title style={{ fontSize: 20, fontWeight: 800 }}>
{user.FirstName} {user.LastName}
</Typography>
<Typography style={{ fontSize: 18, fontWeight: 500 }}>
{message}
</Typography>
</Typography.Title>
<Typography.Text>{message}</Typography.Text>
<Flex gap={0} align="center">
<Button
type="text"

View File

@ -55,31 +55,37 @@ export function Converter({
}
return (
<Typography.Title
editable={{
triggerType: "text" as any,
onChange: (event) => {
onEdit?.(event);
<Input
variant="borderless"
style={{
fontSize: 24,
fontWeight: "bold",
wordBreak: "break-all",
padding: 0,
margin: 0,
}}
placeholder={t("lessonComponentsConverter.titlePlaceholder")}
value={lessonContent.Data}
onChange={(event) => {
onEdit?.(event.target.value);
if (debounceRef.current) {
clearTimeout(debounceRef.current);
}
debounceRef.current = setTimeout(() => {
try {
reqUpdateLessonContent({
lessonId: lessonId,
contentId: lessonContent.Id,
data: event,
data: event.target.value,
});
} catch (err) {
console.error(err);
}
},
}, 1000);
}}
level={1}
style={{
margin: 0,
width: "100%",
}}
>
{lessonContent.Data}
</Typography.Title>
/>
);
case getTypeByName("Text"):
if (mode === "view") {
@ -321,6 +327,7 @@ export function Converter({
}
}}
accept={Constants.ACCEPTED_VIDEO_FILE_TYPES}
fileType="video"
>
<Button type="link">{t("lessonComponentsConverter.video")}</Button>
</MyUpload>

View File

@ -1,7 +1,7 @@
import { Avatar, Checkbox, Collapse, Form, Tooltip } from "antd";
import HeaderBar from "../../core/components/Header";
import MyBanner from "../../shared/components/MyBanner";
import { MyContainer } from "../../shared/components/MyContainer";
import HeaderBar from "core/components/Header";
import MyBanner from "shared/components/MyBanner";
import { MyContainer } from "shared/components/MyContainer";
import MyErrorResult from "shared/components/MyResult";
import MyEmpty from "shared/components/MyEmpty";
import MyCenteredSpin from "shared/components/MyCenteredSpin";
@ -70,6 +70,7 @@ interface Permission {
// test data
/*
const tmpI18nObj = [
{
id: 1,
@ -98,7 +99,7 @@ const tmpI18nObj = [
description:
"Permission to invite a member. An email will be sent to the new member.",
},
];
]; */
/*
export const tmpRoleNames = {
@ -174,7 +175,11 @@ function RoleComponent({ role }: { role: Role }) {
/>
),
extra: (
<>
<div
onClick={(event) => {
event.stopPropagation();
}}
>
{role.Users.length > 0 && (
<Avatar.Group
size="small"
@ -192,14 +197,14 @@ function RoleComponent({ role }: { role: Role }) {
<MyUserAvatar
profilePictureUrl={user.ProfilePictureUrl}
firstName={user.FirstName}
size={32}
size={24}
/>
</div>
</Tooltip>
))}
</Avatar.Group>
)}
</>
</div>
),
},
]}

View File

@ -1,6 +1,6 @@
import { Button, Flex, Form, Input, Modal } from "antd";
import HeaderBar from "../../core/components/Header";
import MyBanner from "../../shared/components/MyBanner";
import HeaderBar from "core/components/Header";
import MyBanner from "shared/components/MyBanner";
import { SaveOutlined } from "@ant-design/icons";
import MyUpload from "shared/components/MyUpload";
import { Constants } from "core/utils/utils";

View File

@ -7,8 +7,8 @@ import {
Select,
Typography,
} from "antd";
import HeaderBar from "../../core/components/Header";
import MyBanner from "../../shared/components/MyBanner";
import HeaderBar from "core/components/Header";
import MyBanner from "shared/components/MyBanner";
import MyMiddleCard from "shared/components/MyMiddleCard";
import Meta from "antd/es/card/Meta";
import { useGetUserProfileQuery } from "core/services/userProfile";

View File

@ -1,5 +1,5 @@
import { CommentOutlined } from "@ant-design/icons";
import { Card, Flex, Typography } from "antd";
import { Card, Flex, Input } from "antd";
import { Constants, getImageUrl } from "core/utils/utils";
import { Link } from "react-router-dom";
import MyUpload from "shared/components/MyUpload";
@ -81,6 +81,22 @@ export default function MyLessonPreviewCard({
{t("lessonPage.questions")}
</div>
) : (
<Input
variant="outlined"
defaultValue={lessonSettings.Title}
onChange={(event) => onEditTitle?.(event.target.value)}
placeholder={t("lessonPageEditor.titlePlaceholder")}
style={{ width: "100%", fontSize: 24, fontWeight: "bold" }}
/>
)}
</Flex>
</div>
</Card>
</LinkWrapper>
);
}
/*
<Typography.Title
level={2}
editable={{
@ -90,14 +106,9 @@ export default function MyLessonPreviewCard({
}}
style={{
width: "100%",
margin: 0,
}}
>
{lessonSettings.Title}
</Typography.Title>
)}
</Flex>
</div>
</Card>
</LinkWrapper>
);
}
*/

View File

@ -8,6 +8,7 @@
.img {
height: 240px;
object-fit: cover;
width: 100%;
}
.title {
@ -23,6 +24,8 @@
.img {
height: 140px;
width: 200px;
min-width: 200px;
}
.title {

View File

@ -24,9 +24,9 @@ const MyUserAvatar: React.FC<MyUserAvatarProps> = ({
const isProfilePictureEmpty = profilePictureUrl === "";
const avatarContent =
isProfilePictureEmpty && firstName !== undefined
? firstName.charAt(0)
: undefined;
isProfilePictureEmpty && firstName !== undefined ? (
<span style={{ fontSize: 16 }}>{firstName.charAt(0)}</span>
) : undefined;
const iconContent =
isProfilePictureEmpty && firstName === undefined ? (
<UserOutlined />