diff --git a/deploy-production.sh b/deploy-production.sh new file mode 100755 index 0000000..7b7baaa --- /dev/null +++ b/deploy-production.sh @@ -0,0 +1,32 @@ +npm run build + +# create zip file of build folder + +zip -r build.zip build + +# connect to server to clear folder + +ssh root@93.177.67.38 << EOF +cd /var/www/html/navilearn-dashboard-web/ +rm -rf * +exit +EOF + +# copy zip file to server + +scp build.zip root@93.177.67.38:/var/www/html/navilearn-dashboard-web/ + +# connect to server + +ssh root@93.177.67.38 << EOF +cd /var/www/html/navilearn-dashboard-web/ +unzip build.zip +mv /var/www/html/navilearn-dashboard-web/build/* /var/www/html/navilearn-dashboard-web/ +rm -rf /var/www/html/navilearn-dashboard-web/build +rm build.zip +exit +EOF + +# remove zip file from local machine + +rm build.zip \ No newline at end of file diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 0000000..3210724 Binary files /dev/null and b/public/apple-touch-icon.png differ diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png new file mode 100644 index 0000000..cbffa3f Binary files /dev/null and b/public/favicon-16x16.png differ diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png new file mode 100644 index 0000000..a4f7d46 Binary files /dev/null and b/public/favicon-32x32.png differ diff --git a/public/favicon.ico b/public/favicon.ico index a11777c..3c1b778 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/index.html b/public/index.html index b4fc862..d8a259a 100644 --- a/public/index.html +++ b/public/index.html @@ -5,39 +5,43 @@ - + - + + + + + - - App +
- diff --git a/public/logo192.png b/public/logo192.png index fc44b0a..2ae03a3 100644 Binary files a/public/logo192.png and b/public/logo192.png differ diff --git a/public/logo512.png b/public/logo512.png index a4e47a6..1c0cf35 100644 Binary files a/public/logo512.png and b/public/logo512.png differ diff --git a/public/manifest.json b/public/manifest.json index 080d6c7..73ca5ce 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,6 +1,6 @@ { - "short_name": "React App", - "name": "Create React App Sample", + "short_name": "NaviLearn", + "name": "NaviLearn", "icons": [ { "src": "favicon.ico", diff --git a/public/mstile-150x150.png b/public/mstile-150x150.png new file mode 100644 index 0000000..bd115ea Binary files /dev/null and b/public/mstile-150x150.png differ diff --git a/src/App.tsx b/src/App.tsx index 264a5c9..ae482f6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,78 +1,124 @@ -import { ConfigProvider, Layout, theme } from 'antd'; -import DashboardLayout from './core/components/DashboardLayout'; -import { darkMode, primaryColor, setBannerUrl, setLogoUrl, setPrimaryColor, setUserAuthenticated, userAuthenticated, setUserProfilePictureUrl } from './core/reducers/appSlice'; -import { useDispatch, useSelector } from 'react-redux'; -import SignIn from './features/Auth/SignIn'; -import { useEffect } from 'react'; -import { myFetch } from './core/utils/utils'; -import MyCenteredSpin from './shared/components/MyCenteredSpin'; -import webSocketService, { WebSocketMessageHandler } from 'core/services/websocketService'; -import { MessageProvider } from 'core/context/MessageContext'; +import { ConfigProvider, Layout, theme } from "antd"; +import DashboardLayout from "./core/components/DashboardLayout"; +import { + darkMode, + primaryColor, + setBannerUrl, + setLogoUrl, + setPrimaryColor, + setUserAuthenticated, + userAuthenticated, + setUserProfilePictureUrl, +} from "./core/reducers/appSlice"; +import { useDispatch, useSelector } from "react-redux"; +import SignIn from "./features/Auth/SignIn"; +import { useEffect } from "react"; +import { myFetch } from "./core/utils/utils"; +import MyCenteredSpin from "./shared/components/MyCenteredSpin"; +import webSocketService, { + WebSocketMessageHandler, +} from "core/services/websocketService"; +import { MessageProvider } from "core/context/MessageContext"; const { defaultAlgorithm, darkAlgorithm } = theme; export default function App() { - const dispatch = useDispatch(); + const dispatch = useDispatch(); - const isDarkMode = useSelector(darkMode); - const uAuthenticated = useSelector(userAuthenticated); - const primColor = useSelector(primaryColor); + const isDarkMode = useSelector(darkMode); + const uAuthenticated = useSelector(userAuthenticated); + const primColor = useSelector(primaryColor); - console.info( - '\n %c LMS %c v1.0.0 %c \n', - 'background-color: #555;color: #fff;padding: 3px 2px 3px 3px;border-radius: 3px 0 0 3px;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)', - 'background-color: #bc81e0;background-image: linear-gradient(90deg, #e67e22, #9b59b6);color: #fff;padding: 3px 3px 3px 2px;border-radius: 0 3px 3px 0;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)', - 'background-color: transparent' - ); + console.info( + "\n %c LMS %c v1.0.0 %c \n", + "background-color: #555;color: #fff;padding: 3px 2px 3px 3px;border-radius: 3px 0 0 3px;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)", + "background-color: #bc81e0;background-image: linear-gradient(90deg, #e67e22, #9b59b6);color: #fff;padding: 3px 3px 3px 2px;border-radius: 0 3px 3px 0;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)", + "background-color: transparent" + ); - useEffect(() => { - if (uAuthenticated) { - (async () => { - try { - const response = await myFetch({ - url: '/app', - method: 'GET', - }); + useEffect(() => { + if (uAuthenticated) { + (async () => { + try { + const response = await myFetch({ + url: "/app", + method: "GET", + }); - if (response) { - dispatch(setPrimaryColor(`#${response.Organization.PrimaryColor}`)); - dispatch(setLogoUrl(response.Organization.LogoUrl)); - dispatch(setBannerUrl(response.Organization.BannerUrl)); - dispatch(setUserProfilePictureUrl(response.User.ProfilePictureUrl)); - dispatch(setUserAuthenticated(true)); - - webSocketService.connect(); - webSocketService.setHandler(WebSocketMessageHandler, dispatch); - } - } catch (error) {} - })(); - - return () => { - webSocketService.disconnect(); - }; - } - }, [uAuthenticated]); - - useEffect(() => { - if (!localStorage.getItem('session')) { - dispatch(setUserAuthenticated(false)); - } else { + if (response) { + dispatch(setPrimaryColor(`#${response.Organization.PrimaryColor}`)); + dispatch(setLogoUrl(response.Organization.LogoUrl)); + dispatch(setBannerUrl(response.Organization.BannerUrl)); + dispatch(setUserProfilePictureUrl(response.User.ProfilePictureUrl)); dispatch(setUserAuthenticated(true)); - } - }, [dispatch]); - return ( - - - {uAuthenticated == null ? : uAuthenticated ? : } - - - ); + webSocketService.connect(); + webSocketService.setHandler(WebSocketMessageHandler, dispatch); + } + } catch (error) {} + })(); + + return () => { + webSocketService.disconnect(); + }; + } + }, [uAuthenticated]); + + useEffect(() => { + const query = new URLSearchParams(window.location.search); + + if (!localStorage.getItem("session") && !query.has("s")) { + dispatch(setUserAuthenticated(false)); + } else if (query.has("s")) { + const searchParam = query.get("s"); + + if (searchParam) { + localStorage.setItem("session", searchParam); + + window.history.replaceState( + {}, + document.title, + window.location.pathname + ); + + dispatch(setUserAuthenticated(true)); + } else { + dispatch(setUserAuthenticated(false)); + } + } else { + dispatch(setUserAuthenticated(true)); + } + }, [dispatch]); + + useEffect(() => { + const plScript = document.createElement("script"); + plScript.src = "https://anal.jannex.de/js/script.js"; + plScript.async = true; + plScript.defer = true; + plScript.setAttribute("data-domain", "dashboard.navilearn.io"); + document.head.appendChild(plScript); + }, []); + + return ( + + + + {uAuthenticated == null ? ( + + ) : uAuthenticated ? ( + + ) : ( + + )} + + + + ); } diff --git a/src/core/components/DashboardLayout/index.tsx b/src/core/components/DashboardLayout/index.tsx index 5ffcd23..abc7315 100644 --- a/src/core/components/DashboardLayout/index.tsx +++ b/src/core/components/DashboardLayout/index.tsx @@ -51,7 +51,7 @@ export default function DashboardLayout() { - + {/* */} diff --git a/src/features/AiChat/index.tsx b/src/features/AiChat/index.tsx index a0e72e2..49a94a6 100644 --- a/src/features/AiChat/index.tsx +++ b/src/features/AiChat/index.tsx @@ -7,9 +7,25 @@ import { getUserSessionFromLocalStorage } from 'core/utils/utils'; import { Marked, marked } from 'marked'; import { createDirectives, presetDirectiveConfigs } from 'marked-directive'; +interface MessageContent { + role?: string; + text?: string; + files?: any[]; + html?: string; +} + +let chatHistory: MessageContent[] = [ + { + text: 'Hallo! Ich bin ein Chatbot. Stell mir Fragen :)', + role: 'ai', + }, +]; + function AiChat() { const [visible, setVisible] = React.useState(false); + //const [chatHistory, setChatHistory] = React.useState([{ text: 'Stell mir Fragen :)', role: 'ai' }]); + return ( <> {visible ? ( @@ -35,7 +51,13 @@ function AiChat() { position: 'absolute', }} avatars={true} - history={[{ text: 'Stell mir Fragen :)', role: 'ai' }]} + history={chatHistory} + onMessage={(message) => { + if (message.isHistory) return; + + //setChatHistory([...chatHistory, message.message]); + chatHistory.push(message.message); + }} connect={{ url: '/api/chat/v1/prompt/', method: 'POST', @@ -63,6 +85,11 @@ function AiChat() { }, }, }} + requestInterceptor={async (requestDetails) => { + console.log(requestDetails); // printed above + requestDetails.body.isFirstMessage = chatHistory.length <= 1; + return requestDetails; + }} responseInterceptor={async (response: any) => { let _response = { ...response }; diff --git a/src/features/Auth/SignIn/styles.module.css b/src/features/Auth/SignIn/styles.module.css index a85661c..c430eea 100644 --- a/src/features/Auth/SignIn/styles.module.css +++ b/src/features/Auth/SignIn/styles.module.css @@ -6,13 +6,13 @@ background-position: center; background-repeat: no-repeat; background-size: cover; - height: 100%; + height: 100vh; width: 100%; } .darkenBackground { position: absolute; background-color: rgba(0, 0, 0, 0.5); - height: 100%; + height: 100vh; width: 100%; } diff --git a/src/features/Settings/index.tsx b/src/features/Settings/index.tsx index 2cfa8ed..c1910d7 100644 --- a/src/features/Settings/index.tsx +++ b/src/features/Settings/index.tsx @@ -412,7 +412,7 @@ function SubdomainCard({ message: t( "organizationSettings.subdomainCard.rules.minLength", { - min: Constants.GLOBALS.MIN_SUBDOMAIN_LENGTH, + minLength: Constants.GLOBALS.MIN_SUBDOMAIN_LENGTH, } ), }, @@ -421,7 +421,7 @@ function SubdomainCard({ message: t( "organizationSettings.subdomainCard.rules.maxLength", { - max: Constants.GLOBALS.MAX_SUBDOMAIN_LENGTH, + maxLength: Constants.GLOBALS.MAX_SUBDOMAIN_LENGTH, } ), },