move all critical components, drop site duck

This commit is contained in:
nick-delirium 2024-09-19 10:38:07 +02:00
parent c2bc023c5e
commit 997d69c389
No known key found for this signature in database
GPG key ID: 93ABD695DF5FDBA0
19 changed files with 108 additions and 267 deletions

View file

@ -14,6 +14,7 @@ import withLocationHandlers from 'HOCs/withLocationHandlers';
import APIClient from 'App/api_client';
import { useLocation } from 'react-router-dom';
import { toast } from 'react-toastify';
import { useStore } from 'App/mstore';
interface Props {
session: Session;
@ -26,7 +27,6 @@ interface Props {
query?: Record<string, (key: string) => any>;
request: () => void;
userId: number;
siteId: number;
}
let playerInst: ILivePlayerContext['player'] | undefined;
@ -40,7 +40,6 @@ function LivePlayer({
query,
isEnterprise,
userId,
siteId,
}: Props) {
// @ts-ignore
const [contextValue, setContextValue] = useState<ILivePlayerContext>(defaultContextValue);
@ -48,8 +47,10 @@ function LivePlayer({
const openedFromMultiview = query?.get('multi') === 'true';
const usedSession = isMultiview ? customSession! : session;
const location = useLocation();
const { projectsStore } = useStore();
useEffect(() => {
const projectId = projectsStore.getSiteId();
playerInst = undefined;
if (!usedSession.sessionId || contextValue.player !== undefined) return;
console.debug('creating live player for', usedSession.sessionId);
@ -69,7 +70,7 @@ function LivePlayer({
sessionWithAgentData,
data,
userId,
siteId,
projectId,
(state) => makeAutoObservable(state),
toast
);
@ -81,7 +82,7 @@ function LivePlayer({
sessionWithAgentData,
null,
userId,
siteId,
projectId,
(state) => makeAutoObservable(state),
toast
);
@ -140,7 +141,6 @@ function LivePlayer({
export default withPermissions(['ASSIST_LIVE', 'SERVICE_ASSIST_LIVE'], '', true, false)(
connect((state: any) => {
return {
siteId: state.getIn([ 'site', 'siteId' ]),
session: state.getIn(['sessions', 'current']),
showAssist: state.getIn(['sessions', 'showChatWindow']),
isEnterprise: state.getIn(['user', 'account', 'edition']) === 'ee',

View file

@ -22,7 +22,8 @@ const ASSIST_ROUTE = assistRoute();
function LivePlayerBlockHeader(props: any) {
const [hideBack, setHideBack] = React.useState(false);
const { store } = React.useContext(PlayerContext);
const { assistMultiviewStore } = useStore();
const { assistMultiviewStore, projectsStore } = useStore();
const siteId = projectsStore.siteId;
const history = useHistory();
const { width, height } = store.get();
@ -30,7 +31,6 @@ function LivePlayerBlockHeader(props: any) {
session,
metaList,
closedLive = false,
siteId,
isMultiview,
} = props;
@ -109,7 +109,6 @@ const PlayerHeaderCont = connect(
isAssist,
session,
sessionPath: state.getIn(['sessions', 'sessionPath']),
siteId: state.getIn(['site', 'siteId']),
metaList: state.getIn(['customFields', 'list']).map((i: any) => i.key),
closedLive: !!state.getIn(['sessions', 'errors']) || (isAssist && !session.live),
};

View file

@ -46,7 +46,7 @@ function Controls(props: any) {
const { player, store } = React.useContext(MobilePlayerContext);
const history = useHistory();
const { playing, completed, skip, speed, messagesLoading } = store.get();
const { uiPlayerStore } = useStore();
const { uiPlayerStore, projectsStore } = useStore();
const fullscreen = uiPlayerStore.fullscreen;
const bottomBlock = uiPlayerStore.bottomBlock;
const toggleBottomBlock = uiPlayerStore.toggleBottomBlock
@ -54,12 +54,12 @@ function Controls(props: any) {
const fullscreenOff = uiPlayerStore.fullscreenOff;
const changeSkipInterval = uiPlayerStore.changeSkipInterval;
const skipInterval = uiPlayerStore.skipInterval;
const siteId = projectsStore.siteId;
const {
session,
setActiveTab,
previousSessionId,
nextSessionId,
siteId,
disableDevtools,
} = props;
@ -289,7 +289,6 @@ export default connect(
totalAssistSessions: state.getIn(['liveSearch', 'total']),
previousSessionId: state.getIn(['sessions', 'previousId']),
nextSessionId: state.getIn(['sessions', 'nextId']),
siteId: state.getIn(['site', 'siteId']),
};
},
{

View file

@ -23,13 +23,12 @@ function PlayerBlockHeader(props: any) {
const playerState = store?.get?.() || { width: 0, height: 0, showEvents: false };
const { width = 0, height = 0, showEvents = false } = playerState;
const { customFieldStore } = useStore();
const { customFieldStore, projectsStore } = useStore();
const siteId = projectsStore.siteId!;
const {
session,
fullscreen,
metaList,
siteId,
setActiveTab,
activeTab,
history,
@ -108,7 +107,6 @@ const PlayerHeaderCont = connect(
sessionPath: state.getIn(['sessions', 'sessionPath']),
local: state.getIn(['sessions', 'timezone']),
funnelRef: state.getIn(['funnels', 'navRef']),
siteId: state.getIn(['site', 'siteId']),
metaList: state.getIn(['customFields', 'list']).map((i: any) => i.key),
};
},

View file

@ -3,7 +3,6 @@ import QueueControls from 'Components/Session_/QueueControls';
import Bookmark from 'Shared/Bookmark';
import Issues from 'Components/Session_/Issues/Issues';
import NotePopup from 'Components/Session_/components/NotePopup';
import { observer } from 'mobx-react-lite';
import { connect } from 'react-redux';
import { Tag } from 'antd'
import { ShareAltOutlined } from '@ant-design/icons';
@ -56,8 +55,7 @@ function SubHeader(props: any) {
}
export default connect((state: any) => ({
siteId: state.getIn(['site', 'siteId']),
modules: state.getIn(['user', 'account', 'modules']) || [],
integrations: state.getIn(['issues', 'list']),
isIOS: state.getIn(['sessions', 'current']).platform === 'ios',
}))(observer(SubHeader));
}))(SubHeader);

View file

@ -24,7 +24,8 @@ const SESSIONS_ROUTE = sessionsRoute();
function PlayerBlockHeader(props: any) {
const [hideBack, setHideBack] = React.useState(false);
const { player, store } = React.useContext(PlayerContext);
const { uxtestingStore, customFieldStore } = useStore()
const { uxtestingStore, customFieldStore, projectsStore } = useStore()
const siteId = projectsStore.siteId!;
const playerState = store?.get?.() || { width: 0, height: 0, showEvents: false }
const { width = 0, height = 0, showEvents = false } = playerState
@ -33,7 +34,6 @@ function PlayerBlockHeader(props: any) {
fullscreen,
metaList,
closedLive = false,
siteId,
setActiveTab,
activeTab,
history,
@ -137,7 +137,6 @@ const PlayerHeaderCont = connect(
sessionPath: state.getIn(['sessions', 'sessionPath']),
local: state.getIn(['sessions', 'timezone']),
funnelRef: state.getIn(['funnels', 'navRef']),
siteId: state.getIn(['site', 'siteId']),
metaList: state.getIn(['customFields', 'list']).map((i: any) => i.key),
};
},

View file

@ -2,7 +2,7 @@ import React from 'react';
import { Button, Checkbox, Input } from 'antd';
import { useHistory } from 'react-router-dom';
import { withSiteId, sessions } from 'App/routes';
import store from 'App/store';
import { useStore } from 'App/mstore';
interface Props {
onSave: (name: string, ignoreClRage: boolean, ignoreDeadCl: boolean) => Promise<any>;
@ -11,6 +11,7 @@ interface Props {
function SaveModal({ onSave, hideModal }: Props) {
const history = useHistory();
const { projectsStore } = useStore();
const [name, setName] = React.useState('');
const [ignoreClRage, setIgnoreClRage] = React.useState(false);
const [ignoreDeadCl, setIgnoreDeadCl] = React.useState(false);
@ -22,7 +23,7 @@ function SaveModal({ onSave, hideModal }: Props) {
const saveAndOpen = () => {
onSave(name, ignoreClRage, ignoreDeadCl).then((tagId) => {
hideModal();
const siteId = store.getState().getIn(['site', 'siteId']);
const siteId = projectsStore.getSiteId() as unknown as string;
history.push(withSiteId(sessions({ tnw: `is|${tagId}`, range: 'LAST_24_HOURS' }), siteId));
});
};

View file

@ -15,20 +15,19 @@ import SessionTileFooter from './SessionTileFooter'
function Multiview({
total,
fetchSessions,
siteId,
assistCredentials,
customSetSessions,
}: {
total: number;
customSetSessions: (data: any) => void;
fetchSessions: (filter: any) => void;
siteId: string;
assistCredentials: any;
list: Record<string, any>[];
}) {
const { showModal, hideModal } = useModal();
const { assistMultiviewStore } = useStore();
const { assistMultiviewStore, projectsStore } = useStore();
const siteId = projectsStore.siteId!;
const history = useHistory();
// @ts-ignore
const { sessionsquery } = useParams();
@ -128,7 +127,6 @@ function Multiview({
export default connect(
(state: any) => ({
total: state.getIn(['liveSearch', 'total']),
siteId: state.getIn(['site', 'siteId']),
}),
{
fetchSessions,

View file

@ -42,9 +42,10 @@ const CurrentTab = React.memo(() => (
</Tab>
));
function AssistTabs({ session, siteId }: { session: Record<string, any>; siteId: string }) {
function AssistTabs({ session }: { session: Record<string, any> }) {
const history = useHistory();
const { assistMultiviewStore } = useStore();
const { assistMultiviewStore, projectsStore } = useStore();
const siteId = projectsStore.siteId!;
const placeholder = new Array(4 - assistMultiviewStore.sessions.length).fill(0);
@ -83,6 +84,4 @@ function AssistTabs({ session, siteId }: { session: Record<string, any>; siteId:
);
}
export default connect((state: any) => ({ siteId: state.getIn(['site', 'siteId']) }))(
observer(AssistTabs)
);
export default observer(AssistTabs)

View file

@ -70,7 +70,7 @@ function getStorageName(type: any) {
function Controls(props: any) {
const { player, store } = React.useContext(PlayerContext);
const { uxtestingStore, uiPlayerStore } = useStore();
const { uxtestingStore, uiPlayerStore, projectsStore } = useStore();
const fullscreen = uiPlayerStore.fullscreen;
const bottomBlock = uiPlayerStore.bottomBlock;
const toggleBottomBlock = uiPlayerStore.toggleBottomBlock;
@ -80,6 +80,7 @@ function Controls(props: any) {
const skipInterval = uiPlayerStore.skipInterval;
const showStorageRedux = !uiPlayerStore.hiddenHints.storage;
const history = useHistory();
const siteId = projectsStore.siteId;
const {
playing,
completed,
@ -95,7 +96,6 @@ function Controls(props: any) {
session,
previousSessionId,
nextSessionId,
siteId,
setActiveTab,
} = props;
@ -440,7 +440,6 @@ export default connect(
totalAssistSessions: state.getIn(['liveSearch', 'total']),
previousSessionId: state.getIn(['sessions', 'previousId']),
nextSessionId: state.getIn(['sessions', 'nextId']),
siteId: state.getIn(['site', 'siteId']),
};
},
{

View file

@ -1,34 +1,40 @@
import { ShareAltOutlined } from '@ant-design/icons';
import { Button as AntButton, Popover, Switch, Tooltip } from 'antd';
import cn from 'classnames';
import { Link2 } from 'lucide-react';
import { observer } from 'mobx-react-lite';
import React, { useMemo } from 'react';
import { connect } from 'react-redux';
import { PlayerContext } from 'App/components/Session/playerContext';
import { IFRAME } from 'App/constants/storageKeys';
import { useStore } from 'App/mstore';
import { checkParam, truncateStringToFit } from 'App/utils';
import SessionTabs from 'Components/Session/Player/SharedComponents/SessionTabs';
import KeyboardHelp from 'Components/Session_/Player/Controls/components/KeyboardHelp';
import { Icon } from 'UI';
import {Link2} from 'lucide-react';
import QueueControls from './QueueControls';
import Bookmark from 'Shared/Bookmark';
import SharePopup from '../shared/SharePopup/SharePopup';
import Issues from './Issues/Issues';
import QueueControls from './QueueControls';
import NotePopup from './components/NotePopup';
import { PlayerContext } from 'App/components/Session/playerContext';
import { observer } from 'mobx-react-lite';
import { connect } from 'react-redux';
import SessionTabs from 'Components/Session/Player/SharedComponents/SessionTabs';
import { IFRAME } from 'App/constants/storageKeys';
import cn from 'classnames';
import { Switch, Button as AntButton, Popover, Tooltip } from 'antd';
import { ShareAltOutlined } from '@ant-design/icons';
import { checkParam, truncateStringToFit } from 'App/utils';
const localhostWarn = (project) => project + '_localhost_warn';
const disableDevtools = 'or_devtools_uxt_toggle';
function SubHeader(props) {
const localhostWarnKey = localhostWarn(props.siteId);
const defaultLocalhostWarn = localStorage.getItem(localhostWarnKey) !== '1';
const { uxtestingStore, projectsStore } = useStore();
const defaultLocalhostWarn = React.useMemo(() => {
const siteId = projectsStore.siteId;
const localhostWarnKey = localhostWarn(siteId);
return localStorage.getItem(localhostWarnKey) !== '1';
}, [projectsStore.siteId]);
const [showWarningModal, setWarning] = React.useState(defaultLocalhostWarn);
const { store } = React.useContext(PlayerContext);
const { location: currentLocation = 'loading...' } = store.get();
const hasIframe = localStorage.getItem(IFRAME) === 'true';
const { uxtestingStore } = useStore();
const [hideTools, setHideTools] = React.useState(false);
React.useEffect(() => {
const hideDevtools = checkParam('hideTools');
@ -46,10 +52,15 @@ function SubHeader(props) {
return integrations.some((i) => i.token);
}, [props.integrations]);
const locationTruncated = truncateStringToFit(currentLocation, window.innerWidth - 200);
const locationTruncated = truncateStringToFit(
currentLocation,
window.innerWidth - 200
);
const showWarning =
currentLocation && /(localhost)|(127.0.0.1)|(0.0.0.0)/.test(currentLocation) && showWarningModal;
currentLocation &&
/(localhost)|(127.0.0.1)|(0.0.0.0)/.test(currentLocation) &&
showWarningModal;
const closeWarning = () => {
localStorage.setItem(localhostWarnKey, '1');
setWarning(false);
@ -65,7 +76,11 @@ function SubHeader(props) {
<div
className="w-full px-4 flex items-center border-b relative"
style={{
background: uxtestingStore.isUxt() ? (props.live ? '#F6FFED' : '#EBF4F5') : undefined
background: uxtestingStore.isUxt()
? props.live
? '#F6FFED'
: '#EBF4F5'
: undefined,
}}
>
{showWarning ? (
@ -77,7 +92,7 @@ function SubHeader(props) {
left: '50%',
bottom: '-24px',
transform: 'translate(-50%, 0)',
fontWeight: 500
fontWeight: 500,
}}
>
Some assets may load incorrectly on localhost.
@ -114,7 +129,10 @@ function SubHeader(props) {
trigger={
<div className="relative">
<Tooltip title="Share Session" placement="bottom">
<AntButton size={'small'} className="flex items-center justify-center">
<AntButton
size={'small'}
className="flex items-center justify-center"
>
<ShareAltOutlined />
</AntButton>
</Tooltip>
@ -141,8 +159,8 @@ function SubHeader(props) {
{locationTruncated && (
<div className={'w-full bg-white border-b border-gray-lighter'}>
<div className="flex w-fit items-center cursor-pointer color-gray-medium text-sm p-1">
<Link2 className="mx-2" size={16} />
<Tooltip title="Open in new tab" delay={0} placement='bottom'>
<Link2 className="mx-2" size={16} />
<Tooltip title="Open in new tab" delay={0} placement="bottom">
<a href={currentLocation} target="_blank" className="truncate">
{locationTruncated}
</a>
@ -155,7 +173,6 @@ function SubHeader(props) {
}
export default connect((state) => ({
siteId: state.getIn(['site', 'siteId']),
integrations: state.getIn(['issues', 'list']),
modules: state.getIn(['user', 'account', 'modules']) || []
modules: state.getIn(['user', 'account', 'modules']) || [],
}))(observer(SubHeader));

View file

@ -1,23 +1,19 @@
import React from 'react';
import { Alert, Space, Button } from 'antd';
import { connect } from 'react-redux';
import { observer } from 'mobx-react-lite'
import { useStore } from "App/mstore";
import { onboarding as onboardingRoute } from 'App/routes';
import { withRouter } from 'react-router-dom';
import * as routes from '../../../routes';
import { indigo } from 'tailwindcss/colors';
import { SquareArrowOutUpRight } from 'lucide-react';
import { useHistory } from 'react-router';
const withSiteId = routes.withSiteId;
const indigoWithOpacity = `rgba(${parseInt(indigo[500].slice(1, 3), 16)}, ${parseInt(indigo[500].slice(3, 5), 16)}, ${parseInt(indigo[500].slice(5, 7), 16)}, 0.1)`; // 0.5 is the opacity level
const NoSessionsMessage = (props) => {
const {
sites,
siteId
} = props;
const NoSessionsMessage = () => {
const { projectsStore } = useStore();
const sites = projectsStore.list;
const siteId = projectsStore.siteId;
const history = useHistory();
const activeSite = sites.find((s) => s.id === siteId);
const showNoSessions = !!activeSite && !activeSite.recorded;
@ -60,7 +56,4 @@ const NoSessionsMessage = (props) => {
);
};
export default connect((state) => ({
site: state.getIn(['site', 'siteId']),
sites: state.getIn(['site', 'list'])
}))(withRouter(NoSessionsMessage));
export default withRouter(observer(NoSessionsMessage));

View file

@ -1,5 +1,4 @@
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { useHistory } from 'react-router';
import {
@ -8,6 +7,7 @@ import {
withSiteId,
} from 'App/routes';
import { Icon, Link } from 'UI';
import { useStore } from 'App/mstore';
const PLAY_ICON_NAMES = {
notPlayed: 'play-fill',
@ -30,6 +30,7 @@ interface Props {
siteId?: string;
}
function PlayLink(props: Props) {
const { projectsStore } = useStore();
const { isAssist, viewed, sessionId, onClick = null, queryParams } = props;
const history = useHistory();
const defaultIconName = getDefaultIconName(viewed);
@ -47,9 +48,10 @@ function PlayLink(props: Props) {
: sessionRoute(sessionId);
const handleBeforeOpen = (e: any) => {
const projectId = props.siteId ?? projectsStore.getSiteId().siteId!;
const replayLink = withSiteId(
link + (props.query ? props.query : ''),
props.siteId
projectId
);
if (props.beforeOpen) {
// check for ctrl or shift
@ -86,6 +88,4 @@ function PlayLink(props: Props) {
);
}
export default connect((state: any, props: Props) => ({
siteId: props.siteId || state.getIn(['site', 'siteId']),
}))(PlayLink);
export default PlayLink

View file

@ -28,8 +28,9 @@ interface Props {
}
function SessionSearch(props: Props) {
const { tagWatchStore, aiFiltersStore } = useStore();
const { appliedFilter, saveRequestPayloads = false, metaLoading = false } = props;
const { tagWatchStore, aiFiltersStore, projectsStore } = useStore();
const saveRequestPayloads = projectsStore.instance?.saveRequestPayloads ?? false
const { appliedFilter, metaLoading = false } = props;
const hasEvents = appliedFilter.filters.filter((i: any) => i.isEvent).size > 0;
const hasFilters = appliedFilter.filters.filter((i: any) => !i.isEvent).size > 0;
@ -154,7 +155,6 @@ function SessionSearch(props: Props) {
export default connect(
(state: any) => ({
saveRequestPayloads: state.getIn(['site', 'instance', 'saveRequestPayloads']),
appliedFilter: state.getIn(['search', 'instance']),
metaLoading: state.getIn(['customFields', 'fetchRequestActive', 'loading']),
}),

View file

@ -3,9 +3,12 @@ import ListingVisibility from './components/ListingVisibility';
import DefaultPlaying from './components/DefaultPlaying';
import DefaultTimezone from './components/DefaultTimezone';
import CaptureRate from './components/CaptureRate';
import { connect } from 'react-redux';
import { observer } from 'mobx-react-lite';
import { useStore } from 'App/mstore';
function SessionSettings({ projectId }: { projectId: number }) {
function SessionSettings() {
const { projectsStore } = useStore();
const projectId = projectsStore.siteId;
return (
<div className='bg-white box-shadow h-screen overflow-y-auto'>
<div className='px-6 pt-6'>
@ -32,6 +35,4 @@ function SessionSettings({ projectId }: { projectId: number }) {
);
}
export default connect((state: any) => ({
projectId: state.getIn(['site', 'siteId'])
}))(SessionSettings);
export default observer(SessionSettings)

View file

@ -11,7 +11,7 @@ import ConditionalRecordingSettings from 'Shared/SessionSettings/components/Cond
type Props = {
isAdmin: boolean;
isEnterprise?: boolean;
projectId?: number;
projectId?: string;
setShowCaptureRate: (show: boolean) => void;
open: boolean;
showCaptureRate: boolean;

View file

@ -1,9 +1,12 @@
import React from 'react';
import { connect } from 'react-redux';
import { observer } from 'mobx-react-lite'
import { useStore } from 'App/mstore'
import Select from 'Shared/Select';
const SiteDropdown = ({ contextName = '', sites, onChange, value }) => {
const options = sites.map(site => ({ value: site.id, label: site.host })).toJS();
const SiteDropdown = ({ contextName = '', onChange, value }) => {
const { projectsStore } = useStore();
const sites = projectsStore.list;
const options = sites.map(site => ({ value: site.id, label: site.host }));
return (
<Select
name={`${contextName}_site`}
@ -17,6 +20,4 @@ const SiteDropdown = ({ contextName = '', sites, onChange, value }) => {
SiteDropdown.displayName = 'SiteDropdown';
export default connect(state => ({
sites: state.getIn(['site', 'list'])
}))(SiteDropdown);
export default observer(SiteDropdown);

View file

@ -1,20 +1,23 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { observer } from 'mobx-react-lite'
import { useStore } from "App/mstore";
import cn from 'classnames';
import { withSiteId } from 'App/routes';
import styles from './link.module.css';
const OpenReplayLink = ({ siteId, to, className="", dispatch, ...other }) => (
<Link
{ ...other }
className={ cn(className, styles.link , 'px-2', 'hover:text-inherit') }
to={ withSiteId(to, siteId) }
/>
);
const OpenReplayLink = ({ siteId, to, className="", dispatch, ...other }) => {
const { projectsStore } = useStore();
const projectId = projectsStore.siteId;
return (
<Link
{ ...other }
className={ cn(className, styles.link , 'px-2', 'hover:text-inherit') }
to={ withSiteId(to, siteId ?? projectId) }
/>
)
};
OpenReplayLink.displayName = 'OpenReplayLink';
export default connect((state, props) => ({
siteId: props.siteId || state.getIn([ 'site', 'siteId' ])
}))(OpenReplayLink);
export default OpenReplayLink;

View file

@ -1,164 +0,0 @@
import Site from "Types/site";
import GDPR from 'Types/site/gdpr';
import {
mergeReducers,
success,
array,
createListUpdater
} from './funcTools/tools';
import {
createCRUDReducer,
getCRUDRequestTypes,
createInit,
createEdit,
createRemove,
createUpdate,
saveType
} from './funcTools/crud';
import { createRequestReducer } from './funcTools/request';
import { Map, List, fromJS } from 'immutable';
import { GLOBAL_HAS_NO_RECORDINGS, SITE_ID_STORAGE_KEY } from 'App/constants/storageKeys';
const storedSiteId = localStorage.getItem(SITE_ID_STORAGE_KEY);
const name = 'project';
const idKey = 'id';
const updateItemInList = createListUpdater(idKey);
const EDIT_GDPR = 'sites/EDIT_GDPR';
const SAVE_GDPR = 'sites/SAVE_GDPR';
const FETCH_GDPR = 'sites/FETCH_GDPR';
const FETCH_LIST = 'sites/FETCH_LIST';
const SET_SITE_ID = 'sites/SET_SITE_ID';
const FETCH_GDPR_SUCCESS = success(FETCH_GDPR);
const SAVE_GDPR_SUCCESS = success(SAVE_GDPR);
const FETCH_LIST_SUCCESS = success(FETCH_LIST);
const SAVE = saveType('sites/SAVE');
const UPDATE_PROJECT_RECORDING_STATUS = 'sites/UPDATE_PROJECT_RECORDING_STATUS';
const initialState = Map({
list: List(),
instance: fromJS(),
remainingSites: undefined,
siteId: null,
active: null
});
const reducer = (state = initialState, action = {}) => {
switch (action.type) {
case EDIT_GDPR:
return state.mergeIn(['instance', 'gdpr'], action.gdpr);
case FETCH_GDPR_SUCCESS:
return state.mergeIn(['instance', 'gdpr'], action.data);
case success(SAVE):
const newSite = Site(action.data);
return updateItemInList(state, newSite)
.set('siteId', newSite.get('id'))
.set('active', newSite);
case SAVE_GDPR_SUCCESS:
const gdpr = GDPR(action.data);
return state.setIn(['instance', 'gdpr'], gdpr);
case FETCH_LIST_SUCCESS:
let siteId = state.get('siteId');
const siteIds = action.data.map(s => parseInt(s.projectId));
const siteExists = siteIds.includes(siteId);
if (action.siteIdFromPath && siteIds.includes(parseInt(action.siteIdFromPath))) {
siteId = action.siteIdFromPath;
} else if (!siteId || !siteExists) {
siteId = siteIds.includes(parseInt(storedSiteId))
? storedSiteId
: action.data[0].projectId;
}
const list = List(action.data.map(Site));
const hasRecordings = list.some(s => s.recorded);
if (!hasRecordings) {
localStorage.setItem(GLOBAL_HAS_NO_RECORDINGS, true);
} else {
localStorage.removeItem(GLOBAL_HAS_NO_RECORDINGS);
}
return state.set('list', list)
.set('siteId', siteId)
.set('active', list.find(s => parseInt(s.id) === parseInt(siteId)));
case SET_SITE_ID:
const _siteId = action.siteId ? action.siteId : state.get('list').get(0).id;
localStorage.setItem(SITE_ID_STORAGE_KEY, _siteId);
const site = state.get('list').find(s => parseInt(s.id) == _siteId);
return state.set('siteId', _siteId).set('active', site);
case UPDATE_PROJECT_RECORDING_STATUS:
const { siteId: _siteIdToUpdate, status } = action;
const siteToUpdate = state.get('list').find(s => parseInt(s.id) === parseInt(_siteIdToUpdate));
const updatedSite = siteToUpdate.set('recorded', status);
return updateItemInList(state, updatedSite);
}
return state;
};
export function editGDPR(gdpr) {
return {
type: EDIT_GDPR,
gdpr
};
}
export function fetchGDPR(siteId) {
return {
types: array(FETCH_GDPR),
call: client => client.get(`/${siteId}/gdpr`)
};
}
export const saveGDPR = (siteId, gdpr) => (dispatch, getState) => {
const g = getState().getIn(['site', 'instance', 'gdpr']);
return dispatch({
types: array(SAVE_GDPR),
call: client => client.post(`/${siteId}/gdpr`, g.toData())
});
};
export function fetchList(siteId) {
return {
types: array(FETCH_LIST),
call: client => client.get('/projects'),
siteIdFromPath: siteId
};
}
export function save(site) {
return {
types: array(SAVE),
call: client => client.post(`/projects`, site.toData())
};
}
// export const fetchList = createFetchList(name);
export const init = createInit(name);
export const edit = createEdit(name);
// export const save = createSave(name);
export const update = createUpdate(name);
export const remove = createRemove(name);
export function setSiteId(siteId) {
return {
type: SET_SITE_ID,
siteId
};
}
export const updateProjectRecordingStatus = (siteId, status) => {
return {
type: UPDATE_PROJECT_RECORDING_STATUS,
siteId,
status
};
};
export default mergeReducers(
reducer,
createCRUDReducer(name, Site, idKey),
createRequestReducer({
saveGDPR: SAVE_GDPR,
...getCRUDRequestTypes(name)
})
);