ui: spot improvs
This commit is contained in:
parent
42b6ae0dfe
commit
420071c436
4 changed files with 80 additions and 43 deletions
|
|
@ -14,14 +14,14 @@ import {
|
|||
} from "App/constants/storageKeys";
|
||||
import Layout from 'App/layout/Layout';
|
||||
import { withStore } from "App/mstore";
|
||||
import { checkParam, handleSpotJWT } from "App/utils";
|
||||
import { checkParam, handleSpotJWT, isTokenExpired } from "App/utils";
|
||||
import { ModalProvider } from 'Components/Modal';
|
||||
import { ModalProvider as NewModalProvider } from 'Components/ModalContext';
|
||||
import { fetchListActive as fetchMetadata } from 'Duck/customField';
|
||||
import { setSessionPath } from 'Duck/sessions';
|
||||
import { fetchList as fetchSiteList } from 'Duck/site';
|
||||
import { init as initSite } from 'Duck/site';
|
||||
import { fetchUserInfo, getScope, setJwt } from "Duck/user";
|
||||
import { fetchUserInfo, getScope, setJwt, logout } from "Duck/user";
|
||||
import { fetchTenants } from 'Duck/user';
|
||||
import { Loader } from 'UI';
|
||||
import { spotsList } from "./routes";
|
||||
|
|
@ -65,11 +65,13 @@ const Router: React.FC<RouterProps> = (props) => {
|
|||
setSessionPath,
|
||||
scopeSetup,
|
||||
localSpotJwt,
|
||||
logout,
|
||||
} = props;
|
||||
|
||||
const params = new URLSearchParams(location.search)
|
||||
const spotCb = params.get('spotCallback');
|
||||
const spotReqSent = React.useRef(false)
|
||||
const [isSpotCb, setIsSpotCb] = React.useState(false);
|
||||
const [isIframe, setIsIframe] = React.useState(false);
|
||||
const [isJwt, setIsJwt] = React.useState(false);
|
||||
|
||||
|
|
@ -135,6 +137,12 @@ const Router: React.FC<RouterProps> = (props) => {
|
|||
handleJwtFromUrl();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (spotCb) {
|
||||
setIsSpotCb(true);
|
||||
}
|
||||
}, [spotCb])
|
||||
|
||||
useEffect(() => {
|
||||
handleDestinationPath();
|
||||
|
||||
|
|
@ -159,9 +167,13 @@ const Router: React.FC<RouterProps> = (props) => {
|
|||
|
||||
useEffect(() => {
|
||||
if (isLoggedIn && location.pathname.includes('login') && localSpotJwt) {
|
||||
handleSpotLogin(localSpotJwt);
|
||||
if (!isTokenExpired(localSpotJwt)) {
|
||||
handleSpotLogin(localSpotJwt);
|
||||
} else if (isSpotCb) {
|
||||
logout();
|
||||
}
|
||||
}
|
||||
}, [location, isLoggedIn, localSpotJwt])
|
||||
}, [isSpotCb, location, isLoggedIn, localSpotJwt])
|
||||
|
||||
useEffect(() => {
|
||||
if (siteId && siteId !== lastFetchedSiteIdRef.current) {
|
||||
|
|
@ -255,6 +267,7 @@ const mapDispatchToProps = {
|
|||
setJwt,
|
||||
fetchMetadata,
|
||||
initSite,
|
||||
logout,
|
||||
};
|
||||
|
||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { ChromeOutlined, ArrowRightOutlined } from '@ant-design/icons';
|
||||
import { Alert, Badge, Button, Modal } from 'antd';
|
||||
import { ArrowUpRight, CirclePlay } from 'lucide-react';
|
||||
import { ChromeOutlined } from '@ant-design/icons';
|
||||
import { Alert, Button, Modal } from 'antd';
|
||||
import { ArrowUpRight } from 'lucide-react';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
function EmptyPage() {
|
||||
|
|
@ -12,7 +12,7 @@ function EmptyPage() {
|
|||
let int: any;
|
||||
const v = localStorage.getItem(extKey);
|
||||
if (v) {
|
||||
setExtExist(true);
|
||||
setExtExist(false);
|
||||
} else {
|
||||
int = setInterval(() => {
|
||||
window.postMessage({ type: 'orspot:ping' }, '*');
|
||||
|
|
@ -50,31 +50,40 @@ function EmptyPage() {
|
|||
'flex flex-col gap-4 items-center w-full p-8 bg-white rounded-lg shadow-sm mt-2'
|
||||
}
|
||||
>
|
||||
|
||||
<div className='w-3/4 flex flex-col gap-3 justify-center items-center '>
|
||||
{extExist ? null : (
|
||||
<Alert
|
||||
message="It looks like you haven’t installed the Spot extension yet."
|
||||
type="warning"
|
||||
action={
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<ChromeOutlined />}
|
||||
className="text-lg"
|
||||
onClick={() => window.open('https://chromewebstore.google.com/detail/openreplay-spot-record-re/ckigbicapkkgfomcfmcbaaplllopgbid?pli=1', '_blank')}
|
||||
>
|
||||
Get Chrome Extension <ArrowUpRight />
|
||||
</Button>
|
||||
}
|
||||
className="w-full justify-between font-medium text-lg rounded-lg border-0"
|
||||
/>
|
||||
<div className="w-3/4 flex flex-col gap-3 justify-center items-center ">
|
||||
{extExist ? null : (
|
||||
<Alert
|
||||
message="It looks like you haven’t installed the Spot extension yet."
|
||||
type="warning"
|
||||
action={
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<ChromeOutlined />}
|
||||
className="text-lg"
|
||||
onClick={() =>
|
||||
window.open(
|
||||
'https://chromewebstore.google.com/detail/openreplay-spot-record-re/ckigbicapkkgfomcfmcbaaplllopgbid?pli=1',
|
||||
'_blank'
|
||||
)
|
||||
}
|
||||
>
|
||||
Get Chrome Extension <ArrowUpRight />
|
||||
</Button>
|
||||
}
|
||||
className="w-full justify-between font-medium text-lg rounded-lg border-0 mb-4"
|
||||
/>
|
||||
)}
|
||||
|
||||
<a href="#" onClick={handleWatchClick} className='rounded-xl overflow-hidden block hover:opacity-75'>
|
||||
<img src='/assets/img/spot-demo-cta.jpg' alt='Learn how to use OpenReplay Spot' />
|
||||
</a>
|
||||
|
||||
<p>Your recordings will appear here.</p>
|
||||
<a
|
||||
href="#"
|
||||
onClick={handleWatchClick}
|
||||
className="rounded-xl overflow-hidden block hover:opacity-75"
|
||||
>
|
||||
<img
|
||||
src="/assets/img/spot-demo-cta.jpg"
|
||||
alt="Learn how to use OpenReplay Spot"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -84,25 +93,24 @@ function EmptyPage() {
|
|||
onCancel={handleModalClose}
|
||||
footer={null}
|
||||
centered
|
||||
className='aspect-video px-0 m-auto'
|
||||
className="aspect-video px-0 m-auto"
|
||||
destroyOnClose={true}
|
||||
width={'820'}
|
||||
>
|
||||
{isModalVisible && (
|
||||
<iframe
|
||||
width='800'
|
||||
height='450'
|
||||
width="800"
|
||||
height="450"
|
||||
src="https://www.youtube.com/embed/A8IzN9MuIYY?autoplay=1"
|
||||
title="YouTube video player"
|
||||
frameBorder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
className='aspect-video m-auto'
|
||||
style={{margin:'auto'}}
|
||||
className="aspect-video m-auto"
|
||||
style={{ margin: 'auto' }}
|
||||
/>
|
||||
)}
|
||||
</Modal>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { makeAutoObservable } from 'mobx';
|
||||
import { loginService } from "../services";
|
||||
import { isTokenExpired } from "../utils";
|
||||
|
||||
const spotTokenKey = "___$or_spotToken$___"
|
||||
|
||||
|
|
@ -12,7 +13,7 @@ class LoginStore {
|
|||
constructor() {
|
||||
makeAutoObservable(this);
|
||||
const token = localStorage.getItem(spotTokenKey);
|
||||
if (token) {
|
||||
if (token && !isTokenExpired(token)) {
|
||||
this.spotJWT = token;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -537,3 +537,18 @@ export const handleSpotJWT = (jwt: string) => {
|
|||
tries += 1;
|
||||
}, 250)
|
||||
}
|
||||
|
||||
export const isTokenExpired = (token: string): boolean => {
|
||||
const decoded: any = decodeJwt(token);
|
||||
const currentTime = Date.now() / 1000;
|
||||
return decoded.exp < currentTime;
|
||||
};
|
||||
|
||||
const decodeJwt = (jwt: string): any => {
|
||||
const base64Url = jwt.split(".")[1];
|
||||
if (!base64Url) {
|
||||
return { exp: 0 };
|
||||
}
|
||||
const base64 = base64Url.replace("-", "+").replace("_", "/");
|
||||
return JSON.parse(atob(base64));
|
||||
};
|
||||
Loading…
Add table
Reference in a new issue