showing incoming text mesages in chat window

This commit is contained in:
Nuwan Chathuranga 2021-09-20 14:22:01 +05:30 committed by Nuwan
parent 7c60153c21
commit 89b3273125
26 changed files with 644 additions and 397 deletions

View File

@ -1736,6 +1736,24 @@
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz",
"integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw=="
}, },
"@reduxjs/toolkit": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.6.1.tgz",
"integrity": "sha512-pa3nqclCJaZPAyBhruQtiRwtTjottRrVJqziVZcWzI73i6L3miLTtUyWfauwv08HWtiXLx1xGyGt+yLFfW/d0A==",
"requires": {
"immer": "^9.0.1",
"redux": "^4.1.0",
"redux-thunk": "^2.3.0",
"reselect": "^4.0.0"
},
"dependencies": {
"immer": {
"version": "9.0.6",
"resolved": "https://registry.npmjs.org/immer/-/immer-9.0.6.tgz",
"integrity": "sha512-G95ivKpy+EvVAnAab4fVa4YGYn24J1SpEktnJX7JJ45Bd7xqME/SCplFzYFmTbrkwZbQ4xJK1xMTUYBkN6pWsQ=="
}
}
},
"@svgr/babel-plugin-add-jsx-attribute": { "@svgr/babel-plugin-add-jsx-attribute": {
"version": "4.2.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz",
@ -15328,6 +15346,11 @@
"@babel/runtime": "^7.9.2" "@babel/runtime": "^7.9.2"
} }
}, },
"redux-thunk": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
"integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw=="
},
"regenerate": { "regenerate": {
"version": "1.4.2", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@ -15631,6 +15654,11 @@
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
}, },
"reselect": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz",
"integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA=="
},
"resize-observer-polyfill": { "resize-observer-polyfill": {
"version": "1.5.1", "version": "1.5.1",
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",

View File

@ -17,6 +17,7 @@
"@fullcalendar/react": "^5.3.1", "@fullcalendar/react": "^5.3.1",
"@fullcalendar/timegrid": "^5.3.1", "@fullcalendar/timegrid": "^5.3.1",
"@loadable/component": "^5.13.2", "@loadable/component": "^5.13.2",
"@reduxjs/toolkit": "^1.6.1",
"attr-accept": "^2.2.2", "attr-accept": "^2.2.2",
"bootstrap": "^4.5.3", "bootstrap": "^4.5.3",
"chart.js": "^2.9.3", "chart.js": "^2.9.3",

View File

@ -1,63 +1,16 @@
import React from 'react'; import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom'; import { BrowserRouter as Router } from 'react-router-dom';
import Layout from './layouts/Layout'; import JKLayout from './layouts/JKLayout';
import 'react-toastify/dist/ReactToastify.min.css'; import 'react-toastify/dist/ReactToastify.min.css';
import 'react-datetime/css/react-datetime.css'; import 'react-datetime/css/react-datetime.css';
import 'react-image-lightbox/style.css'; import 'react-image-lightbox/style.css';
import useScript from './hooks/useScript';
import { useDispatch } from "react-redux";
//import { addMessage } from "./store/features/textMessagesSlice"
const App = () => { const App = () => {
function initJKScripts() {
const app = window.JK.JamKazam();
const jamServer = new window.JK.JamServer(app, function(event_type) {
console.log('---EVENT_TYPE---', event_type);
//return app.activeElementEvent(event_type)
});
jamServer.initialize();
window.JK.initJamClient(app);
const clientInit = new window.JK.ClientInit();
clientInit.init();
window.JK.JamServer.connect() // singleton here defined in JamServer.js
.done(function() {
console.log('Jamserver connected');
//_initAfterConnect(true);
})
.fail(function() {
console.log('Jamserver connection error');
//_initAfterConnect(false);
});
registerTextMessageCallback();
}
function registerTextMessageCallback(){
window.JK.JamServer.registerMessageCallback(window.JK.MessageType.TEXT_MESSAGE, function(header, payload) {
console.log('Handling TEXT_MESSAGE ' + JSON.stringify(payload));
// chatMessageReceived(payload);
// context.ChatActions.msgReceived(payload);
// handledNotification(payload);
//dispatch(addMessage())
});
}
const dispatch = useDispatch()
useScript(`${process.env.REACT_APP_LEGACY_BASE_URL}/client_scripts`, initJKScripts);
return ( return (
<Router basename={process.env.PUBLIC_URL}> <Router basename={process.env.PUBLIC_URL}>
<Layout /> <JKLayout />
</Router> </Router>
); );
}; };

View File

@ -0,0 +1,29 @@
import React from 'react'
import { Card, CardBody, Row, Col } from 'reactstrap';
import Logo from '../navbar/Logo';
import Section from '../common/Section';
function JKLoginRequest() {
return (
<Section className="py-0">
<Row className="flex-center min-vh-100 py-6">
<Col sm={10} md={8} lg={6} xl={5} className="col-xxl-4">
<Logo />
<Card>
<CardBody className="fs--1 font-weight-normal p-5">
<Row className="justify-content-center">
<h3 className="mt-3 mt-md-4 font-weight-normal fs-2">Signin to begin</h3>
<p>Please login to your jamkazam account before accessing this interface.</p>
<a className="btn btn-primary" href="https://www.jamkazam.com/signin">
Signin
</a>
</Row>
</CardBody>
</Card>
</Col>
</Row>
</Section>
)
}
export default JKLoginRequest

View File

@ -0,0 +1,11 @@
import React from 'react'
function JKDashboardLoadingIndicator() {
return (
<div className="spinner-border" role="status">
<span className="sr-only">Loading...</span>
</div>
)
}
export default JKDashboardLoadingIndicator

View File

@ -1,10 +1,93 @@
import React from "react"; import React, { useContext, useEffect } from 'react';
const JKDashboard = () => { import { Route, Switch } from 'react-router-dom';
return( import NavbarTop from '../navbar/NavbarTop';
<h1>Dashboard</h1> import NavbarVertical from '../navbar/NavbarVertical';
) import JKFooter from '../footer/JKFooter';
import AppContext from '../../context/Context';
import { getPageName } from '../../helpers/utils';
import useScript from '../../hooks/useScript';
import { useDispatch } from "react-redux";
import { addMessage } from "../../store/features/textMessagesSlice"
import JKHome from './JkHome';
import loadable from '@loadable/component';
const JKDashboardRoutes = loadable(() => import('../../layouts/JKDashboardRoutes'));
function JKDashboard() {
const { isFluid, isVertical, navbarStyle } = useContext(AppContext);
const isKanban = getPageName('kanban');
useEffect(() => {
JKDashboardRoutes.preload();
}, []);
const dispatch = useDispatch()
const initJKScripts = () => {
const app = window.JK.JamKazam();
const jamServer = new window.JK.JamServer(app, function(event_type) {
console.log('EVENT_TYPE', event_type);
});
jamServer.initialize();
window.JK.initJamClient(app);
const clientInit = new window.JK.ClientInit();
clientInit.init();
window.JK.JamServer.connect() // singleton here defined in JamServer.js
.done(function() {
console.log('Jamserver connected');
//_initAfterConnect(true);
})
.fail(function() {
console.log('Jamserver connection error');
//_initAfterConnect(false);
});
registerTextMessageCallback();
}
const registerTextMessageCallback = () => {
window.JK.JamServer.registerMessageCallback(window.JK.MessageType.TEXT_MESSAGE, function(header, payload) {
const json = payload
const receivedMsg = {
id: json.text_message_id,
message: json.msg,
senderId: json.sender_id,
senderName: json.sender_name,
receiverId: window.currentUser.id,
receiverName: window.currentUser.first_name,
createdAt: json.created_at,
sent: true
}
dispatch(addMessage(receivedMsg))
});
}
useScript(`${process.env.REACT_APP_LEGACY_BASE_URL}/client_scripts`, initJKScripts);
return (
<div className={isFluid || isKanban ? 'container-fluid' : 'container'}>
{isVertical && <NavbarVertical isKanban={isKanban} navbarStyle={navbarStyle} />}
<div className="content">
<NavbarTop />
<Switch>
<Route path="/" exact component={JKHome} />
<JKDashboardRoutes />
</Switch>
{!isKanban && <JKFooter />}
</div>
{/* <SidePanelModal path={location.pathname} /> */}
</div>
);
} }
export default JKDashboard; export default JKDashboard;

View File

@ -0,0 +1,10 @@
import React from "react";
const JKHome = () => {
return(
<h1>Dashboard - Home</h1>
)
}
export default JKHome;

View File

@ -0,0 +1,20 @@
import React from 'react';
import { Col, Row } from 'reactstrap';
import { version } from '../../config';
const JKFooter = () => (
<footer>
<Row noGutters className="justify-content-between text-center fs--1 mt-4 mb-3">
<Col sm="auto">
<p className="mb-0 text-600">
Copyright &copy; {new Date().getFullYear()} JamKazam, Inc. All Rights Reserved
</p>
</Col>
<Col sm="auto">
<p className="mb-0 text-600">v{version}</p>
</Col>
</Row>
</footer>
);
export default JKFooter;

View File

@ -1,5 +1,5 @@
import React, { useEffect, useState, useRef } from 'react'; import React, { useEffect, useState, useRef } from 'react';
import { Modal, ModalHeader, ModalBody, Row, Col, Button, ModalFooter } from 'reactstrap'; import { Modal, ModalHeader, ModalBody, Row, Col, Button, ModalFooter, Badge } from 'reactstrap';
import { Scrollbar } from 'react-scrollbars-custom'; import { Scrollbar } from 'react-scrollbars-custom';
import TimeAgo from 'react-timeago'; import TimeAgo from 'react-timeago';
import JKProfileAvatar from './JKProfileAvatar'; import JKProfileAvatar from './JKProfileAvatar';
@ -11,31 +11,40 @@ const JKMessageModal = props => {
const { show, setShow, user } = props; const { show, setShow, user } = props;
const LIMIT = 20; const LIMIT = 20;
const [fetching, setFetching] = useState(false);
const [offset, setOffset] = useState(0); const [offset, setOffset] = useState(0);
const [newMessage, setNewMessage] = useState(''); const [newMessage, setNewMessage] = useState('');
const [messagesArrived, setMessagesArrived] = useState(false);
const toggle = () => setShow(!show); const toggle = () => setShow(!show);
const { currentUser } = useAuth(); const { currentUser } = useAuth();
const dispatch = useDispatch(); const dispatch = useDispatch();
const scrollbar = useRef(); const scrollbar = useRef();
const messageTextBox = useRef();
const scrolledToBottom = useRef(false);
const messages = useSelector(state => const messages = useSelector(state =>
state.textMessage.messages state.textMessage.messages
.filter( .filter(
message => message =>
(message.senderId === user.id && message.receiverId === currentUser.id) || (message.senderId === user.id && message.receiverId === window.currentUser.id) ||
(message.senderId === currentUser.id && message.receiverId === user.id) (message.senderId === window.currentUser.id && message.receiverId === user.id)
) )
.reverse() .sort((a, b) => {
return new Date(a.createdAt) - new Date(b.createdAt);
})
); );
const fetchMessages = async () => { const fetchMessages = async () => {
try { try {
await dispatch(fetchMessagesByReceiverId(user.id)).unwrap(); const options = { userId: user.id, offset: offset, limit: LIMIT };
scrollbar.current.scrollToBottom(); setFetching(true);
await dispatch(fetchMessagesByReceiverId(options)).unwrap();
} catch (err) { } catch (err) {
console.log('ERROR', err); console.log('ERROR', err);
} finally {
setFetching(false);
} }
}; };
@ -48,37 +57,102 @@ const JKMessageModal = props => {
}; };
setNewMessage(''); setNewMessage('');
await dispatch(postNewMessage(msgData)).unwrap(); await dispatch(postNewMessage(msgData)).unwrap();
fetchMessages();
} catch (err) { } catch (err) {
console.log('addNewMessage error', err); console.log('addNewMessage error', err);
} finally { } finally {
} }
}; };
const handleOnKeyPress = (event) => { const handleOnKeyPress = event => {
//console.log('event', event.key); if (event.key === 'Enter' || event.key === 'NumpadEnter') {
if(event.key === 'Enter' || event.key === "NumpadEnter"){ event.preventDefault();
sendMessage() sendMessage();
event.target.value = '';
} }
} };
const scrollAtTop = () => {
return scrollbar.current.scrollTop === 0;
};
const scrollAtMiddle = () => {
return scrollbar.current.scrollHeight - scrollbar.current.clientHeight > scrollbar.current.scrollTop;
};
const scrollAtBottom = () => {
return scrollbar.current.scrollHeight - scrollbar.current.clientHeight === scrollbar.current.scrollTop;
};
const goToBottom = () => {
if (scrollbar && scrollbar.current) {
scrollbar.current.scrollToBottom();
}
};
useEffect(() => { useEffect(() => {
if (show) { if (show && messages.length === 0) {
//console.log('JKMessageModal User', user.id);
fetchMessages(); fetchMessages();
} }
}, [show, dispatch]); }, [show]);
useEffect(() => {
if (scrollbar && scrollbar.current) {
if (!fetching && !scrollAtTop()) {
if (messages[messages.length - 1]['senderId'] !== currentUser.id) {
if (!scrolledToBottom.current) {
setMessagesArrived(true);
} else {
goToBottom();
}
} else {
goToBottom();
}
}
}
}, [messages]);
useEffect(() => {
if (!messagesArrived) {
setMessagesArrived(false);
goToBottom();
}
}, [messagesArrived]);
const handleScrollStop = scrollValues => {
scrolledToBottom.current = false;
if (scrollValues.scrollTop === 0) {
setOffset(prev => prev + 1);
} else if (scrollValues.scrollTop === scrollValues.scrollHeight - scrollValues.clientHeight) {
scrolledToBottom.current = true;
setMessagesArrived(false);
}
};
useEffect(() => {
if (offset !== 0) {
fetchMessages();
}
}, [offset]);
return ( return (
<> <>
<Modal isOpen={show} toggle={toggle}> <Modal isOpen={show} toggle={toggle}>
<ModalHeader toggle={toggle}>Conversation with {user.name}</ModalHeader> <ModalHeader toggle={toggle}>Conversation with {user.name}</ModalHeader>
<ModalBody> <ModalBody>
<Scrollbar ref={scrollbar} style={{ width: '100%', height: 200 }}> <Scrollbar
ref={scrollbar}
onScrollStop={handleScrollStop}
style={{ width: '100%', height: 200 }}
mobileNative={true}
trackClickBehavior="step"
>
{messages.map((message, index) => ( {messages.map((message, index) => (
<div className="d-flex mb-3 mr-1" key={message.id}> <div className="d-flex mb-3 mr-1" key={message.id}>
<div className="avatar avatar-2xl d-inline-block"> <div className="avatar avatar-2xl d-inline-block">
<JKProfileAvatar url={ message.receiverId === currentUser.id ? currentUser.photo_url : user.photo_url} /> <JKProfileAvatar
url={message.receiverId === currentUser.id ? currentUser.photo_url : user.photo_url}
/>
</div> </div>
<div className="d-inline-block"> <div className="d-inline-block">
<div className="d-flex flex-column"> <div className="d-flex flex-column">
@ -93,6 +167,9 @@ const JKMessageModal = props => {
if (unit === 'minute') return `${value} ${value === 1 ? 'minute' : 'minutes'} ago`; if (unit === 'minute') return `${value} ${value === 1 ? 'minute' : 'minutes'} ago`;
if (unit === 'hour') return `${value} ${value === 1 ? 'hour' : 'hours'} ago`; if (unit === 'hour') return `${value} ${value === 1 ? 'hour' : 'hours'} ago`;
if (unit === 'day') return `${value} ${value === 1 ? 'day' : 'days'} ago`; if (unit === 'day') return `${value} ${value === 1 ? 'day' : 'days'} ago`;
if (unit === 'week') return `${value} ${value === 1 ? 'week' : 'weeks'} ago`;
if (unit === 'month') return `${value} ${value === 1 ? 'month' : 'months'} ago`;
if (unit === 'year') return `${value} ${value === 1 ? 'year' : 'years'} ago`;
}} }}
/> />
</time> </time>
@ -103,9 +180,24 @@ const JKMessageModal = props => {
</div> </div>
))} ))}
</Scrollbar> </Scrollbar>
{messagesArrived && (
<Row>
<Col className="d-flex justify-content-center">
<Button color="info" size="sm" onClick={() => setMessagesArrived(prev => !prev)}>
New messages
</Button>
</Col>
</Row>
)}
<Row> <Row>
<Col> <Col>
<textarea style={{ width: '100%' }} value={newMessage} onChange={e => setNewMessage(e.target.value)} onKeyPress={handleOnKeyPress} /> <textarea
style={{ width: '100%' }}
value={newMessage}
onChange={e => setNewMessage(e.target.value)}
onKeyPress={handleOnKeyPress}
ref={messageTextBox}
/>
</Col> </Col>
</Row> </Row>
</ModalBody> </ModalBody>

View File

@ -13,6 +13,7 @@ import JKProfileGenres from './JKProfileGenres';
import JKProfilePerformanceSamples from './JKProfilePerformanceSamples'; import JKProfilePerformanceSamples from './JKProfilePerformanceSamples';
import { useAuth } from '../../context/AuthContext'; import { useAuth } from '../../context/AuthContext';
import JKConnectButton from './JKConnectButton'; import JKConnectButton from './JKConnectButton';
import JKMessageButton from './JKMessageButton';
import JKLatencyBadge from './JKLatencyBadge'; import JKLatencyBadge from './JKLatencyBadge';
import JKLastActiveAgo from './JKLastActiveAgo'; import JKLastActiveAgo from './JKLastActiveAgo';
import JKProfileSkillLevel from './JKProfileSkillLevel'; import JKProfileSkillLevel from './JKProfileSkillLevel';
@ -139,9 +140,13 @@ const JKProfileSidePanel = props => {
</> </>
} }
/>{' '} />{' '}
<button className="btn btn-outline-primary" data-testid="message"> {/* <button className="btn btn-outline-primary" data-testid="message">
<span className="fas fa-comment" /> Send Message <span className="fas fa-comment" /> Send Message
</button> </button> */}
<JKMessageButton currentUser={currentUser} user={user}>
<FontAwesomeIcon icon="comments" transform="shrink-4 down-1" className="mr-1" /> Send Message
</JKMessageButton>
</div> </div>
)} )}
</div> </div>

View File

@ -1,5 +1,5 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
const useScript = (src, onloadHandler) => { const useScript = (src, onloadHandler = () => {}) => {
useEffect(() => { useEffect(() => {
const script = document.createElement('script'); const script = document.createElement('script');
script.src = src; script.src = src;

View File

@ -1,61 +1,23 @@
import React, { useState, useContext, useEffect } from 'react'; import React, { useContext, useEffect } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Route, Switch, Redirect, NavLink } from 'react-router-dom'; import { Route, Switch } from 'react-router-dom';
import { Card, CardBody, Row, Col, Button } from 'reactstrap'; import Dashboard from '../components/dashboard/Dashboard';
import Logo from '../components/navbar/Logo'; import DashboardAlt from '../components/dashboard-alt/DashboardAlt';
import Section from '../components/common/Section';
//import Dashboard from '../components/dashboard/Dashboard';
import JKDashboard from '../components/dashboard/JkDashboard';
//import DashboardAlt from '../components/dashboard-alt/DashboardAlt';
import NavbarTop from '../components/navbar/NavbarTop'; import NavbarTop from '../components/navbar/NavbarTop';
import NavbarVertical from '../components/navbar/NavbarVertical'; import NavbarVertical from '../components/navbar/NavbarVertical';
import Footer from '../components/footer/Footer'; import Footer from '../components/footer/Footer';
import loadable from '@loadable/component'; import loadable from '@loadable/component';
import AppContext from '../context/Context'; import AppContext from '../context/Context';
import ProductProvider from '../components/e-commerce/ProductProvider'; import ProductProvider from '../components/e-commerce/ProductProvider';
// import SidePanelModal from '../components/side-panel/SidePanelModal'; import SidePanelModal from '../components/side-panel/SidePanelModal';
import { getPageName } from '../helpers/utils'; import { getPageName } from '../helpers/utils';
import { useAuth } from '../context/AuthContext';
import { getCurrentUser } from '../helpers/rest';
const AUTH_STAGES = {
loading: 1,
authenticated: 2,
unauthenticated: 3
};
const DashboardRoutes = loadable(() => import('./DashboardRoutes')); const DashboardRoutes = loadable(() => import('./DashboardRoutes'));
const DashboardLayout = ({ location }) => { const DashboardLayout = ({ location }) => {
const { isFluid, isVertical, navbarStyle } = useContext(AppContext);
const { currentUser, setCurrentUser } = useAuth(); const isKanban = getPageName('kanban');
const [stage, setStage] = useState(AUTH_STAGES['loading']);
const fetchCurrentUser = () => {
getCurrentUser()
.then(resp => {
if (resp.ok) {
return resp.json();
}
})
.then(data => {
console.log('layout CURRENT_USER', data);
setCurrentUser(data);
setStage(AUTH_STAGES['authenticated']);
})
.catch(error => {
setStage(AUTH_STAGES['unauthenticated']);
console.log(error);
});
};
useEffect(() => {
fetchCurrentUser();
}, []);
useEffect(() => { useEffect(() => {
DashboardRoutes.preload(); DashboardRoutes.preload();
@ -65,84 +27,22 @@ const DashboardLayout = ({ location }) => {
window.scrollTo(0, 0); window.scrollTo(0, 0);
}, [location.pathname]); }, [location.pathname]);
switch (stage) {
case AUTH_STAGES['authenticated']:
return <DashboardSection />;
case AUTH_STAGES['unauthenticated']:
return <LoginRequestSection />;
default:
return <DashboardLoadingIndicator />;
}
};
const DashboardLoadingIndicator = () => {
return ( return (
<div className="spinner-border" role="status">
<span className="sr-only">Loading...</span>
</div>
);
};
const LoginRequestSection = () => {
return (
<Section className="py-0">
<Row className="flex-center min-vh-100 py-6">
<Col sm={10} md={8} lg={6} xl={5} className="col-xxl-4">
<Logo />
<Card>
<CardBody className="fs--1 font-weight-normal p-5">
<Row className="justify-content-center">
<h3 className="mt-3 mt-md-4 font-weight-normal fs-2">Signin to begin</h3>
<p>Please login to your jamkazam account before accessing this interface.</p>
<a className="btn btn-primary" href="https://www.jamkazam.com/signin">
Signin
</a>
</Row>
</CardBody>
</Card>
</Col>
</Row>
</Section>
);
};
const DashboardSection = () => {
const { isFluid, isVertical, navbarStyle } = useContext(AppContext);
const isKanban = getPageName('kanban');
return (
<div className={isFluid || isKanban ? 'container-fluid' : 'container'}> <div className={isFluid || isKanban ? 'container-fluid' : 'container'}>
{isVertical && <NavbarVertical isKanban={isKanban} navbarStyle={navbarStyle} />} {isVertical && <NavbarVertical isKanban={isKanban} navbarStyle={navbarStyle} />}
<ProductProvider> <ProductProvider>
<div className="content"> <div className="content">
<NavbarTop /> <NavbarTop />
<Switch> <Switch>
{/* <Route path="/" exact component={Dashboard} /> */} <Route path="/" exact component={Dashboard} />
{/* <Route path="/dashboard-alt" exact component={DashboardAlt} /> */} <Route path="/dashboard-alt" exact component={DashboardAlt} />
<Route path="/" exact component={JKDashboard} />
<DashboardRoutes /> <DashboardRoutes />
</Switch> </Switch>
{!isKanban && <Footer />} {!isKanban && <Footer />}
</div> </div>
{/* <SidePanelModal path={location.pathname} /> */} <SidePanelModal path={location.pathname} />
</ProductProvider> </ProductProvider>
</div> </div>
);
};
const ProtectedRoute = ({ component: Component, ...rest }) => {
const { currentUser } = useAuth();
return (
// Show the component only when the user is logged in
// Otherwise, redirect the user to /login page
<Route
{...rest}
render={props =>
currentUser ? <Component {...props} /> : <Redirect to={{ pathname: '/authentication/basic/start' }} />
}
/>
); );
}; };

View File

@ -1,153 +1,148 @@
import { fn } from 'moment';
import React from 'react'; import React from 'react';
import { Redirect, Route, Switch } from 'react-router-dom'; import { Redirect, Route, Switch } from 'react-router-dom';
// import Alerts from '../components/bootstrap-components/Alerts'; import Alerts from '../components/bootstrap-components/Alerts';
// import Avatar from '../components/bootstrap-components/Avatar'; import Avatar from '../components/bootstrap-components/Avatar';
// import AutocompleteExample from '../components/bootstrap-components/AutocompleteExample'; import AutocompleteExample from '../components/bootstrap-components/AutocompleteExample';
// import Backgrounds from '../components/bootstrap-components/Backgrounds'; import Backgrounds from '../components/bootstrap-components/Backgrounds';
// import Badges from '../components/bootstrap-components/Badges'; import Badges from '../components/bootstrap-components/Badges';
// import Breadcrumbs from '../components/bootstrap-components/Breadcrumb'; import Breadcrumbs from '../components/bootstrap-components/Breadcrumb';
// import Buttons from '../components/bootstrap-components/Buttons'; import Buttons from '../components/bootstrap-components/Buttons';
// import Cards from '../components/bootstrap-components/Cards'; import Cards from '../components/bootstrap-components/Cards';
// import Carousel from '../components/bootstrap-components/Carousel'; import Carousel from '../components/bootstrap-components/Carousel';
// import Collapses from '../components/bootstrap-components/Collapses'; import Collapses from '../components/bootstrap-components/Collapses';
// import Combo from '../components/bootstrap-components/Combo'; import Combo from '../components/bootstrap-components/Combo';
// import CookieNotice from '../components/bootstrap-components/CookieNotice'; import CookieNotice from '../components/bootstrap-components/CookieNotice';
// import Dropdowns from '../components/bootstrap-components/Dropdowns'; import Dropdowns from '../components/bootstrap-components/Dropdowns';
// import FalconAccordions from '../components/bootstrap-components/FalconAccordions'; import FalconAccordions from '../components/bootstrap-components/FalconAccordions';
// import Forms from '../components/bootstrap-components/Forms'; import Forms from '../components/bootstrap-components/Forms';
// import ListGroups from '../components/bootstrap-components/ListGroups'; import ListGroups from '../components/bootstrap-components/ListGroups';
// import Modals from '../components/bootstrap-components/Modals'; import Modals from '../components/bootstrap-components/Modals';
// import Navbars from '../components/bootstrap-components/Navbars'; import Navbars from '../components/bootstrap-components/Navbars';
// import NavBarTop from '../components/bootstrap-components/NavBarTop'; import NavBarTop from '../components/bootstrap-components/NavBarTop';
// import Navs from '../components/bootstrap-components/Navs'; import Navs from '../components/bootstrap-components/Navs';
// import PageHeaders from '../components/bootstrap-components/PageHeaders'; import PageHeaders from '../components/bootstrap-components/PageHeaders';
// import Paginations from '../components/bootstrap-components/Paginations'; import Paginations from '../components/bootstrap-components/Paginations';
// import Popovers from '../components/bootstrap-components/Popovers'; import Popovers from '../components/bootstrap-components/Popovers';
// import ProgressBar from '../components/bootstrap-components/ProgressBar'; import ProgressBar from '../components/bootstrap-components/ProgressBar';
// import Sidepanel from '../components/bootstrap-components/Sidepanel'; import Sidepanel from '../components/bootstrap-components/Sidepanel';
// import Spinners from '../components/bootstrap-components/Spinners'; import Spinners from '../components/bootstrap-components/Spinners';
// import Tables from '../components/bootstrap-components/Tables'; import Tables from '../components/bootstrap-components/Tables';
// import Tabs from '../components/bootstrap-components/Tabs'; import Tabs from '../components/bootstrap-components/Tabs';
// import Tooltips from '../components/bootstrap-components/Tooltips'; import Tooltips from '../components/bootstrap-components/Tooltips';
// import VerticalNavbar from '../components/bootstrap-components/VerticalNavbar'; import VerticalNavbar from '../components/bootstrap-components/VerticalNavbar';
// import Calendar from '../components/calendar/Calendar'; import Calendar from '../components/calendar/Calendar';
// import ChangeLog from '../components/changelog/ChangeLog'; import ChangeLog from '../components/changelog/ChangeLog';
// import Chat from '../components/chat/Chat'; import Chat from '../components/chat/Chat';
// import GettingStarted from '../components/documentation/GettingStarted'; import GettingStarted from '../components/documentation/GettingStarted';
// import Checkout from '../components/e-commerce/Checkout'; import Checkout from '../components/e-commerce/Checkout';
// import Customers from '../components/e-commerce/Customers'; import Customers from '../components/e-commerce/Customers';
// import FavouriteItems from '../components/e-commerce/FavouriteItems'; import FavouriteItems from '../components/e-commerce/FavouriteItems';
// import OrderDetails from '../components/e-commerce/OrderDetails'; import OrderDetails from '../components/e-commerce/OrderDetails';
// import Orders from '../components/e-commerce/Orders'; import Orders from '../components/e-commerce/Orders';
// import ProductDetails from '../components/e-commerce/ProductDetails'; import ProductDetails from '../components/e-commerce/ProductDetails';
// import Products from '../components/e-commerce/Products'; import Products from '../components/e-commerce/Products';
// import ShoppingCart from '../components/e-commerce/ShoppingCart'; import ShoppingCart from '../components/e-commerce/ShoppingCart';
// import Compose from '../components/email/Compose'; import Compose from '../components/email/Compose';
// import EmailDetail from '../components/email/EmailDetail'; import EmailDetail from '../components/email/EmailDetail';
// import Inbox from '../components/email/Inbox'; import Inbox from '../components/email/Inbox';
// import InboxProvider from '../components/email/inbox/InboxProvider'; import InboxProvider from '../components/email/inbox/InboxProvider';
// import Starter from '../components/extra/Starter'; import Starter from '../components/extra/Starter';
// import Feed from '../components/feed/Feed'; import Feed from '../components/feed/Feed';
// import Kanban from '../components/kanban/Kanban'; import Kanban from '../components/kanban/Kanban';
// import Activity from '../components/page/Activity'; import Activity from '../components/page/Activity';
// import Associations from '../components/page/Associations'; import Associations from '../components/page/Associations';
// import Billing from '../components/page/Billing'; import Billing from '../components/page/Billing';
// import CustomerDetails from '../components/page/CustomerDetails'; import CustomerDetails from '../components/page/CustomerDetails';
// import EventCreate from '../components/page/EventCreate'; import EventCreate from '../components/page/EventCreate';
// import EventDetail from '../components/page/EventDetail'; import EventDetail from '../components/page/EventDetail';
// import Events from '../components/page/Events'; import Events from '../components/page/Events';
// import Faq from '../components/page/Faq'; import Faq from '../components/page/Faq';
// import InvitePeople from '../components/page/InvitePeople'; import InvitePeople from '../components/page/InvitePeople';
// import Invoice from '../components/page/Invoice'; import Invoice from '../components/page/Invoice';
// import Notifications from '../components/page/Notifications'; import Notifications from '../components/page/Notifications';
// import People from '../components/page/People'; import People from '../components/page/People';
// import Settings from '../components/page/Settings'; import Settings from '../components/page/Settings';
// import BulkSelect from '../components/plugins/BulkSelect'; import BulkSelect from '../components/plugins/BulkSelect';
// import CalendarExample from '../components/plugins/CalendarExample'; import CalendarExample from '../components/plugins/CalendarExample';
// import Chart from '../components/plugins/Chart'; import Chart from '../components/plugins/Chart';
// import CodeHighlightDoc from '../components/plugins/CodeHighlightDoc'; import CodeHighlightDoc from '../components/plugins/CodeHighlightDoc';
// import CountUpExample from '../components/plugins/Countup'; import CountUpExample from '../components/plugins/Countup';
// import DatetimeExample from '../components/plugins/Datetime'; import DatetimeExample from '../components/plugins/Datetime';
// import Dropzone from '../components/plugins/Dropzone'; import Dropzone from '../components/plugins/Dropzone';
// import EchartMap from '../components/plugins/EchartMap'; import EchartMap from '../components/plugins/EchartMap';
// import Echarts from '../components/plugins/Echarts'; import Echarts from '../components/plugins/Echarts';
// import EmojiMart from '../components/plugins/EmojiMart'; import EmojiMart from '../components/plugins/EmojiMart';
// import FontAwesome from '../components/plugins/FontAwesome'; import FontAwesome from '../components/plugins/FontAwesome';
// import GoogleMapExample from '../components/plugins/GoogleMap'; import GoogleMapExample from '../components/plugins/GoogleMap';
// import ImageLightbox from '../components/plugins/ImageLightbox'; import ImageLightbox from '../components/plugins/ImageLightbox';
// import Leaflet from '../components/plugins/Leaflet'; import Leaflet from '../components/plugins/Leaflet';
// import Lottie from '../components/plugins/Lottie'; import Lottie from '../components/plugins/Lottie';
// import Plyr from '../components/plugins/Plyr'; import Plyr from '../components/plugins/Plyr';
// import ProgressBarJs from '../components/plugins/ProgressBarJs'; import ProgressBarJs from '../components/plugins/ProgressBarJs';
// import QuillEditorExample from '../components/plugins/Quill'; import QuillEditorExample from '../components/plugins/Quill';
// import ReactBeautifulDnD from '../components/plugins/ReactBeautifulDnD'; import ReactBeautifulDnD from '../components/plugins/ReactBeautifulDnD';
// import ReactBootstrapTable2 from '../components/plugins/ReactBootstrapTable2'; import ReactBootstrapTable2 from '../components/plugins/ReactBootstrapTable2';
// import ReactHookFrom from '../components/plugins/ReactHookFrom'; import ReactHookFrom from '../components/plugins/ReactHookFrom';
// import Scrollbar from '../components/plugins/Scrollbar'; import Scrollbar from '../components/plugins/Scrollbar';
// import Select from '../components/plugins/Select'; import Select from '../components/plugins/Select';
// import SlickCarousel from '../components/plugins/SlickCarousel'; import SlickCarousel from '../components/plugins/SlickCarousel';
// import Toastify from '../components/plugins/Toastify'; import Toastify from '../components/plugins/Toastify';
// import Typed from '../components/plugins/Typed'; import Typed from '../components/plugins/Typed';
// import Pricing from '../components/pricing/Pricing'; import Pricing from '../components/pricing/Pricing';
// import PricingAlt from '../components/pricing/PricingAlt'; import PricingAlt from '../components/pricing/PricingAlt';
// import Profile from '../components/profile/Profile'; import Profile from '../components/profile/Profile';
// import Borders from '../components/utilities/Borders'; import Borders from '../components/utilities/Borders';
// import Clearfix from '../components/utilities/Clearfix'; import Clearfix from '../components/utilities/Clearfix';
// import CloseIcon from '../components/utilities/CloseIcon'; import CloseIcon from '../components/utilities/CloseIcon';
// import Colors from '../components/utilities/Colors'; import Colors from '../components/utilities/Colors';
// import Display from '../components/utilities/Display'; import Display from '../components/utilities/Display';
// import Embed from '../components/utilities/Embed'; import Embed from '../components/utilities/Embed';
// import Figures from '../components/utilities/Figures'; import Figures from '../components/utilities/Figures';
// import Flex from '../components/utilities/Flex'; import Flex from '../components/utilities/Flex';
// import Grid from '../components/utilities/Grid'; import Grid from '../components/utilities/Grid';
// import Sizing from '../components/utilities/Sizing'; import Sizing from '../components/utilities/Sizing';
// import Spacing from '../components/utilities/Spacing'; import Spacing from '../components/utilities/Spacing';
// import StretchedLink from '../components/utilities/StretchedLink'; import StretchedLink from '../components/utilities/StretchedLink';
// import Typography from '../components/utilities/Typography'; import Typography from '../components/utilities/Typography';
// import VerticalAlign from '../components/utilities/VerticalAlign'; import VerticalAlign from '../components/utilities/VerticalAlign';
// import Visibility from '../components/utilities/Visibility'; import Visibility from '../components/utilities/Visibility';
// import Widgets from '../components/widgets/Widgets'; import Widgets from '../components/widgets/Widgets';
import JKPeople from '../components/page/JKPeople';
// const InboxRoutes = ({ match: { url } }) => ( const InboxRoutes = ({ match: { url } }) => (
// <InboxProvider> <InboxProvider>
// <Switch> <Switch>
// <Route path={`${url}/email-detail`} exact component={EmailDetail} /> <Route path={`${url}/email-detail`} exact component={EmailDetail} />
// <Route path={`${url}/inbox`} exact component={Inbox} /> <Route path={`${url}/inbox`} exact component={Inbox} />
// <Route path={`${url}/compose`} exact component={Compose} /> <Route path={`${url}/compose`} exact component={Compose} />
// {/*Redirect*/} {/*Redirect*/}
// <Redirect to="/errors/404" /> <Redirect to="/errors/404" />
// </Switch> </Switch>
// </InboxProvider> </InboxProvider>
// ); );
// const ProductRoutes = ({ match: { url } }) => ( const ProductRoutes = ({ match: { url } }) => (
// <Switch> <Switch>
// <Route path={`${url}/products/:productLayout`} exact component={Products} /> <Route path={`${url}/products/:productLayout`} exact component={Products} />
// <Route path={`${url}/checkout`} exact component={Checkout} /> <Route path={`${url}/checkout`} exact component={Checkout} />
// <Route path={`${url}/product-details/:id`} exact component={ProductDetails} /> <Route path={`${url}/product-details/:id`} exact component={ProductDetails} />
// <Route path={`${url}/product-details/`} exact component={ProductDetails} /> <Route path={`${url}/product-details/`} exact component={ProductDetails} />
// <Route path={`${url}/shopping-cart`} exact component={ShoppingCart} /> <Route path={`${url}/shopping-cart`} exact component={ShoppingCart} />
// <Route path={`${url}/orders`} exact component={Orders} /> <Route path={`${url}/orders`} exact component={Orders} />
// <Route path={`${url}/order-details`} exact component={OrderDetails} /> <Route path={`${url}/order-details`} exact component={OrderDetails} />
// <Route path={`${url}/customers`} exact component={Customers} /> <Route path={`${url}/customers`} exact component={Customers} />
// <Route path={`${url}/favourite-items`} exact component={FavouriteItems} /> <Route path={`${url}/favourite-items`} exact component={FavouriteItems} />
// {/*Redirect*/} {/*Redirect*/}
// <Redirect to="/errors/404" /> <Redirect to="/errors/404" />
// </Switch> </Switch>
// ); );
const DashboardRoutes = () => ( const DashboardRoutes = () => (
<Switch> <Switch>
<Route path="/friends" component={JKPeople} /> <Route path="/feed" exact component={Feed} />
{/* <Route path="/feed" exact component={Feed} /> */}
{/*Pages*/} {/*Pages*/}
{/* <Route path="/pages/activity" exact component={Activity} /> <Route path="/pages/activity" exact component={Activity} />
<Route path="/pages/associations" exact component={Associations} /> <Route path="/pages/associations" exact component={Associations} />
<Route path="/pages/billing" exact component={Billing} /> <Route path="/pages/billing" exact component={Billing} />
<Route path="/pages/customer-details" exact component={CustomerDetails} /> <Route path="/pages/customer-details" exact component={CustomerDetails} />
@ -163,30 +158,30 @@ const DashboardRoutes = () => (
<Route path="/pages/pricing-alt" exact component={PricingAlt} /> <Route path="/pages/pricing-alt" exact component={PricingAlt} />
<Route path="/pages/profile" exact component={Profile} /> <Route path="/pages/profile" exact component={Profile} />
<Route path="/pages/settings" exact component={Settings} /> <Route path="/pages/settings" exact component={Settings} />
<Route path="/pages/starter" exact component={Starter} /> */} <Route path="/pages/starter" exact component={Starter} />
{/*chat*/} {/*chat*/}
{/* <Route path="/chat" exact component={Chat} /> */} <Route path="/chat" exact component={Chat} />
{/*calendar*/} {/*calendar*/}
{/* <Route path="/calendar" exact component={Calendar} /> */} <Route path="/calendar" exact component={Calendar} />
{/*kanban*/} {/*kanban*/}
{/* <Route path="/kanban" exact component={Kanban} /> */} <Route path="/kanban" exact component={Kanban} />
{/*E commerce*/} {/*E commerce*/}
{/* <Route path="/e-commerce" component={ProductRoutes} /> */} <Route path="/e-commerce" component={ProductRoutes} />
{/*Email*/} {/*Email*/}
{/* <Route path="/email" component={InboxRoutes} /> */} <Route path="/email" component={InboxRoutes} />
{/*widgets*/} {/*widgets*/}
{/* <Route path="/widgets" component={Widgets} /> */} <Route path="/widgets" component={Widgets} />
{/*Documentation*/} {/*Documentation*/}
{/* <Route path="/documentation" exact component={GettingStarted} /> */} <Route path="/documentation" exact component={GettingStarted} />
{/*Changelog*/} {/*Changelog*/}
{/* <Route path="/changelog" exact component={ChangeLog} /> */} <Route path="/changelog" exact component={ChangeLog} />
{/*Components*/} {/*Components*/}
{/* <Route path="/components/alerts" exact component={Alerts} /> <Route path="/components/alerts" exact component={Alerts} />
<Route path="/components/autocomplete" exact component={AutocompleteExample} /> <Route path="/components/autocomplete" exact component={AutocompleteExample} />
<Route path="/components/accordions" exact component={FalconAccordions} /> <Route path="/components/accordions" exact component={FalconAccordions} />
<Route path="/components/avatar" exact component={Avatar} /> <Route path="/components/avatar" exact component={Avatar} />
@ -215,10 +210,10 @@ const DashboardRoutes = () => (
<Route path="/components/tables" exact component={Tables} /> <Route path="/components/tables" exact component={Tables} />
<Route path="/components/tooltips" exact component={Tooltips} /> <Route path="/components/tooltips" exact component={Tooltips} />
<Route path="/components/spinners" exact component={Spinners} /> <Route path="/components/spinners" exact component={Spinners} />
<Route path="/components/carousel" exact component={Carousel} /> */} <Route path="/components/carousel" exact component={Carousel} />
{/*Utilities*/} {/*Utilities*/}
{/* <Route path="/utilities/borders" exact component={Borders} /> <Route path="/utilities/borders" exact component={Borders} />
<Route path="/utilities/clearfix" exact component={Clearfix} /> <Route path="/utilities/clearfix" exact component={Clearfix} />
<Route path="/utilities/closeIcon" exact component={CloseIcon} /> <Route path="/utilities/closeIcon" exact component={CloseIcon} />
<Route path="/utilities/colors" exact component={Colors} /> <Route path="/utilities/colors" exact component={Colors} />
@ -232,10 +227,10 @@ const DashboardRoutes = () => (
<Route path="/utilities/stretchedLink" exact component={StretchedLink} /> <Route path="/utilities/stretchedLink" exact component={StretchedLink} />
<Route path="/utilities/typography" exact component={Typography} /> <Route path="/utilities/typography" exact component={Typography} />
<Route path="/utilities/verticalAlign" exact component={VerticalAlign} /> <Route path="/utilities/verticalAlign" exact component={VerticalAlign} />
<Route path="/utilities/visibility" exact component={Visibility} /> */} <Route path="/utilities/visibility" exact component={Visibility} />
{/*Plugins*/} {/*Plugins*/}
{/* <Route path="/plugins/calendar-example" exact component={CalendarExample} /> <Route path="/plugins/calendar-example" exact component={CalendarExample} />
<Route path="/plugins/bulk-select" exact component={BulkSelect} /> <Route path="/plugins/bulk-select" exact component={BulkSelect} />
<Route path="/plugins/typed" exact component={Typed} /> <Route path="/plugins/typed" exact component={Typed} />
<Route path="/plugins/image-lightbox" exact component={ImageLightbox} /> <Route path="/plugins/image-lightbox" exact component={ImageLightbox} />
@ -260,12 +255,11 @@ const DashboardRoutes = () => (
<Route path="/plugins/code-highlight" exact component={CodeHighlightDoc} /> <Route path="/plugins/code-highlight" exact component={CodeHighlightDoc} />
<Route path="/plugins/emoji-mart" exact component={EmojiMart} /> <Route path="/plugins/emoji-mart" exact component={EmojiMart} />
<Route path="/plugins/react-bootstrap-table2" exact component={ReactBootstrapTable2} /> <Route path="/plugins/react-bootstrap-table2" exact component={ReactBootstrapTable2} />
<Route path="/plugins/react-beautiful-dnd" exact component={ReactBeautifulDnD} /> */} <Route path="/plugins/react-beautiful-dnd" exact component={ReactBeautifulDnD} />
{/*Redirect*/} {/*Redirect*/}
<Redirect to="/errors/404" /> <Redirect to="/errors/404" />
</Switch> </Switch>
); );
export default DashboardRoutes; export default DashboardRoutes;

View File

@ -0,0 +1,76 @@
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { Route, Redirect } from 'react-router-dom';
import JKDashboardLoadingIndicator from '../components/dashboard/JKDashboardLoadingIndicator';
import JKLoginRequest from '../components/auth/JKLoginRequest';
import JKDashboard from '../components/dashboard/JKDashboard';
import { useAuth } from '../context/AuthContext';
import { getCurrentUser } from '../helpers/rest';
const AUTH_STAGES = {
loading: 1,
authenticated: 2,
unauthenticated: 3
};
const JKDashboardLayout = ({ location }) => {
const { setCurrentUser } = useAuth();
const [stage, setStage] = useState(AUTH_STAGES['loading']);
const fetchCurrentUser = () => {
getCurrentUser()
.then(resp => {
if (resp.ok) {
return resp.json();
}
})
.then(user => {
setCurrentUser(user);
window.currentUser = user;
setStage(AUTH_STAGES['authenticated']);
})
.catch(error => {
setStage(AUTH_STAGES['unauthenticated']);
console.log(error);
});
};
useEffect(() => {
fetchCurrentUser();
}, []);
useEffect(() => {
window.scrollTo(0, 0);
}, [location.pathname]);
switch (stage) {
case AUTH_STAGES['authenticated']:
return <JKDashboard />;
case AUTH_STAGES['unauthenticated']:
return <JKLoginRequest />;
default:
return <JKDashboardLoadingIndicator />;
}
};
const ProtectedRoute = ({ component: Component, ...rest }) => {
const { currentUser } = useAuth();
return (
// Show the component only when the user is logged in
// Otherwise, redirect the user to /login page
<Route
{...rest}
render={props =>
currentUser ? <Component {...props} /> : <Redirect to={{ pathname: '/authentication/basic/start' }} />
}
/>
);
};
JKDashboardLayout.propTypes = { location: PropTypes.object.isRequired };
export default JKDashboardLayout;

View File

@ -0,0 +1,15 @@
import React from 'react';
import { Redirect, Route, Switch } from 'react-router-dom';
import JKPeople from '../components/page/JKPeople';
const JKDashboardRoutes = () => (
<Switch>
<Route path="/friends" component={JKPeople} />
{/*Redirect*/}
<Redirect to="/errors/404" />
</Switch>
);
export default JKDashboardRoutes;

View File

@ -0,0 +1,22 @@
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { toast, ToastContainer } from 'react-toastify';
import { CloseButton, Fade } from '../components/common/Toast';
import JKDashboardLayout from './JKDashboardLayout';
import ErrorLayout from './ErrorLayout';
const JKLayout = () => {
return (
<Router fallback={<span />}>
<Switch>
<Route path="/errors" component={ErrorLayout} />
<Route component={JKDashboardLayout} />
</Switch>
<ToastContainer transition={Fade} closeButton={<CloseButton />} position={toast.POSITION.BOTTOM_LEFT} />
</Router>
);
};
export default JKLayout;

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { toast, ToastContainer } from 'react-toastify'; import { toast, ToastContainer } from 'react-toastify';
import { CloseButton, Fade } from '../components/common/Toast'; import { CloseButton, Fade } from '../components/common/Toast';
@ -6,42 +6,33 @@ import { CloseButton, Fade } from '../components/common/Toast';
import DashboardLayout from './DashboardLayout'; import DashboardLayout from './DashboardLayout';
import ErrorLayout from './ErrorLayout'; import ErrorLayout from './ErrorLayout';
import loadable from '@loadable/component';
const AuthBasicLayout = loadable(() => import('./AuthBasicLayout'));
// import loadable from '@loadable/component'; const Landing = loadable(() => import('../components/landing/Landing'));
const WizardLayout = loadable(() => import('../components/auth/wizard/WizardLayout'));
//const AuthBasicLayout = loadable(() => import('./AuthBasicLayout')); const AuthCardRoutes = loadable(() => import('../components/auth/card/AuthCardRoutes'));
//const Landing = loadable(() => import('../components/landing/Landing')); const AuthSplitRoutes = loadable(() => import('../components/auth/split/AuthSplitRoutes'));
//const WizardLayout = loadable(() => import('../components/auth/wizard/WizardLayout'));
//const AuthCardRoutes = loadable(() => import('../components/auth/card/AuthCardRoutes'));
//const AuthSplitRoutes = loadable(() => import('../components/auth/split/AuthSplitRoutes'));
const Layout = () => { const Layout = () => {
useEffect(() => { useEffect(() => {
//AuthBasicLayout.preload(); AuthBasicLayout.preload();
//Landing.preload(); Landing.preload();
//WizardLayout.preload(); WizardLayout.preload();
//AuthCardRoutes.preload(); AuthCardRoutes.preload();
//AuthSplitRoutes.preload(); AuthSplitRoutes.preload();
}, []); }, []);
return ( return (
<Router fallback={<span />}> <Router fallback={<span />}>
<Switch> <Switch>
{/* <Route path="/friends" exact component={PeopleList} /> */} <Route path="/landing" exact component={Landing} />
{/* <Route path="/landing" exact component={Landing} /> */} <Route path="/authentication/card" component={AuthCardRoutes} />
{/* <Route path="/authentication/card" component={AuthCardRoutes} /> <Route path="/authentication/split" component={AuthSplitRoutes} />
<Route path="/authentication/split" component={AuthSplitRoutes} /> <Route path="/authentication/wizard" component={WizardLayout} />
<Route path="/authentication/wizard" component={WizardLayout} /> */}
<Route path="/errors" component={ErrorLayout} /> <Route path="/errors" component={ErrorLayout} />
{/* <Route path="/authentication/basic" component={AuthBasicLayout} /> */} <Route path="/authentication/basic" component={AuthBasicLayout} />
<Route component={DashboardLayout} /> <Route component={DashboardLayout} />
</Switch> </Switch>
<ToastContainer transition={Fade} closeButton={<CloseButton />} position={toast.POSITION.BOTTOM_LEFT} /> <ToastContainer transition={Fade} closeButton={<CloseButton />} position={toast.POSITION.BOTTOM_LEFT} />
</Router> </Router>
); );

View File

@ -4,37 +4,33 @@ import { getTextMessages, createTextMessage } from '../../helpers/rest';
const initialState = { const initialState = {
messages: [], messages: [],
status: 'idel', status: 'idel',
error: null, error: null
offset: 0
} }
// const [offset, setOffset] = useState(0);
// const LIMIT = 20;
export const fetchMessagesByReceiverId = createAsyncThunk( export const fetchMessagesByReceiverId = createAsyncThunk(
'textMessage/fetchMessagesByReceiverId', 'textMessage/fetchMessagesByReceiverId',
async (userId, thunkAPI) => { async (options, thunkAPI) => {
const { userId, offset, limit } = options
const response = await getTextMessages({ const response = await getTextMessages({
target_user_id: userId target_user_id: userId,
// offset: offset, offset: offset,
// limit: LIMIT limit: limit
}) })
return response.json() return response.json()
} }
) )
export const resturectureTextMessage = (args) => { export const resturectureTextMessage = (args) => {
const { payload, sent } = args const { message, sent } = args
//console.log(payload); const messageId = message.id ? message.id : nanoid()
const messageId = payload.id ? payload.id : nanoid() const createdAt = message.created_at ? message.created_at : new Date().toISOString()
const createdAt = payload.created_at ? payload.created_at : new Date().toISOString()
return { return {
id: messageId, id: messageId,
message: payload.message, message: message.message,
senderId: payload.source_user_id, senderId: message.source_user_id,
senderName: payload.source_user['first_name'], senderName: message.source_user['name'],
receiverId: payload.target_user_id, receiverId: message.target_user_id,
receiverName: payload.target_user['first_name'], receiverName: message.target_user['name'],
createdAt: createdAt, createdAt: createdAt,
sent: sent sent: sent
} }
@ -44,7 +40,7 @@ export const postNewMessage = createAsyncThunk(
'textMessage/postNewMessage', 'textMessage/postNewMessage',
async (message, thunkAPI) => { async (message, thunkAPI) => {
const response = await createTextMessage(message) const response = await createTextMessage(message)
return { status: response.status, payload: message } return response.json()
} }
) )
@ -65,8 +61,11 @@ export const textMessageSlice = createSlice({
}) })
.addCase(fetchMessagesByReceiverId.fulfilled, (state, action) => { .addCase(fetchMessagesByReceiverId.fulfilled, (state, action) => {
state.status = 'succeeded' state.status = 'succeeded'
console.log(action.payload); const msgs = action.payload.map(message => resturectureTextMessage({ message, sent: true }))
state.messages = action.payload.map(message => resturectureTextMessage({ payload: message, sent: true })) const mergedMsgs = [...state.messages, ...msgs]
const unique = [];
mergedMsgs.map(x => unique.filter(a => a.id == x.id).length > 0 ? null : unique.push(x));
state.messages = unique
}) })
.addCase(fetchMessagesByReceiverId.rejected, (state, action) => { .addCase(fetchMessagesByReceiverId.rejected, (state, action) => {
state.status = 'failed' state.status = 'failed'
@ -74,6 +73,7 @@ export const textMessageSlice = createSlice({
}) })
.addCase(postNewMessage.fulfilled, (state, action) => { .addCase(postNewMessage.fulfilled, (state, action) => {
console.log("postNewMessage fullfilled", action.payload); console.log("postNewMessage fullfilled", action.payload);
state.messages.push(resturectureTextMessage({ message: action.payload, sent: true }))
}) })
} }
}) })

1
pb/.gitignore vendored
View File

@ -3,3 +3,4 @@ target
*~ *~
bin bin
.bundle .bundle
.ruby-version

View File

@ -631,6 +631,7 @@ message TextMessage {
optional string notification_id = 5; optional string notification_id = 5;
optional string created_at = 6; optional string created_at = 6;
optional bool clipped_msg = 7; optional bool clipped_msg = 7;
optional string text_message_id = 8;
} }
message ChatMessage { message ChatMessage {

View File

@ -985,7 +985,7 @@ module JamRuby
end end
# creates the general purpose text message # creates the general purpose text message
def text_message(receiver_id, sender_photo_url, sender_name, sender_id, msg, clipped_msg, notification_id, created_at) def text_message(receiver_id, sender_photo_url, sender_name, sender_id, msg, clipped_msg, notification_id, created_at, text_message_id)
text_message = Jampb::TextMessage.new( text_message = Jampb::TextMessage.new(
:photo_url => sender_photo_url, :photo_url => sender_photo_url,
:sender_name => sender_name, :sender_name => sender_name,
@ -993,7 +993,8 @@ module JamRuby
:msg => msg, :msg => msg,
:clipped_msg => clipped_msg, :clipped_msg => clipped_msg,
:notification_id => notification_id, :notification_id => notification_id,
:created_at => created_at :created_at => created_at,
text_message_id: text_message_id
) )
Jampb::ClientMessage.new( Jampb::ClientMessage.new(

View File

@ -1522,7 +1522,7 @@ module JamRuby
end end
end end
def send_text_message(message, sender, receiver) def send_text_message(message, sender, receiver, text_message_id)
notification = Notification.new notification = Notification.new
notification.description = NotificationTypes::TEXT_MESSAGE notification.description = NotificationTypes::TEXT_MESSAGE
@ -1542,7 +1542,9 @@ module JamRuby
truncated_msg, truncated_msg,
msg_is_clipped, msg_is_clipped,
notification.id, notification.id,
notification.created_date) notification.created_date,
text_message_id
)
logger.debug('-' * 30) logger.debug('-' * 30)
logger.debug(msg) logger.debug(msg)
logger.debug('-' * 30) logger.debug('-' * 30)

View File

@ -55,7 +55,7 @@ module JamRuby
tm.save tm.save
# send notification # send notification
@notification = Notification.send_text_message(sanitized_text, User.find(source_user_id), User.find(target_user_id)) @notification = Notification.send_text_message(sanitized_text, User.find(source_user_id), User.find(target_user_id), tm.id)
tm tm
end end

View File

@ -12,7 +12,8 @@ class ApiTextMessagesController < ApiController
def create def create
@text_message = TextMessage.create(params[:message], params[:target_user_id], current_user.id) @text_message = TextMessage.create(params[:message], params[:target_user_id], current_user.id)
respond_with_model(@text_message, new: true) #respond_with_model(@text_message, new: true)
respond_with @text_message
end end
end end

View File

@ -0,0 +1,11 @@
object @text_message
attributes :id, :source_user_id, :target_user_id, :message, :created_at
child :source_user => :source_user do |msg|
attributes :id, :name
end
child :target_user => :target_user do |msg|
attributes :id, :name
end

View File

@ -3,9 +3,9 @@ collection @text_messages
attributes :id, :source_user_id, :target_user_id, :message, :created_at attributes :id, :source_user_id, :target_user_id, :message, :created_at
child :source_user => :source_user do |msg| child :source_user => :source_user do |msg|
attributes :id, :name, :first_name attributes :id, :name
end end
child :target_user => :target_user do |msg| child :target_user => :target_user do |msg|
attributes :id, :name, :first_name attributes :id, :name
end end