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",
"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": {
"version": "4.2.0",
"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"
}
},
"redux-thunk": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
"integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw=="
},
"regenerate": {
"version": "1.4.2",
"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",
"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": {
"version": "1.5.1",
"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/timegrid": "^5.3.1",
"@loadable/component": "^5.13.2",
"@reduxjs/toolkit": "^1.6.1",
"attr-accept": "^2.2.2",
"bootstrap": "^4.5.3",
"chart.js": "^2.9.3",

View File

@ -1,63 +1,16 @@
import React from 'react';
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-datetime/css/react-datetime.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 = () => {
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 (
<Router basename={process.env.PUBLIC_URL}>
<Layout />
<JKLayout />
</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(
<h1>Dashboard</h1>
)
import NavbarTop from '../navbar/NavbarTop';
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;

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 { 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 TimeAgo from 'react-timeago';
import JKProfileAvatar from './JKProfileAvatar';
@ -11,31 +11,40 @@ const JKMessageModal = props => {
const { show, setShow, user } = props;
const LIMIT = 20;
const [fetching, setFetching] = useState(false);
const [offset, setOffset] = useState(0);
const [newMessage, setNewMessage] = useState('');
const [messagesArrived, setMessagesArrived] = useState(false);
const toggle = () => setShow(!show);
const { currentUser } = useAuth();
const dispatch = useDispatch();
const scrollbar = useRef();
const messageTextBox = useRef();
const scrolledToBottom = useRef(false);
const messages = useSelector(state =>
state.textMessage.messages
.filter(
message =>
(message.senderId === user.id && message.receiverId === currentUser.id) ||
(message.senderId === currentUser.id && message.receiverId === user.id)
(message.senderId === user.id && message.receiverId === window.currentUser.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 () => {
try {
await dispatch(fetchMessagesByReceiverId(user.id)).unwrap();
scrollbar.current.scrollToBottom();
const options = { userId: user.id, offset: offset, limit: LIMIT };
setFetching(true);
await dispatch(fetchMessagesByReceiverId(options)).unwrap();
} catch (err) {
console.log('ERROR', err);
} finally {
setFetching(false);
}
};
@ -48,37 +57,102 @@ const JKMessageModal = props => {
};
setNewMessage('');
await dispatch(postNewMessage(msgData)).unwrap();
fetchMessages();
} catch (err) {
console.log('addNewMessage error', err);
} finally {
}
};
const handleOnKeyPress = (event) => {
//console.log('event', event.key);
if(event.key === 'Enter' || event.key === "NumpadEnter"){
sendMessage()
const handleOnKeyPress = event => {
if (event.key === 'Enter' || event.key === 'NumpadEnter') {
event.preventDefault();
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(() => {
if (show) {
//console.log('JKMessageModal User', user.id);
if (show && messages.length === 0) {
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 (
<>
<Modal isOpen={show} toggle={toggle}>
<ModalHeader toggle={toggle}>Conversation with {user.name}</ModalHeader>
<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) => (
<div className="d-flex mb-3 mr-1" key={message.id}>
<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 className="d-inline-block">
<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 === 'hour') return `${value} ${value === 1 ? 'hour' : 'hours'} 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>
@ -103,9 +180,24 @@ const JKMessageModal = props => {
</div>
))}
</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>
<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>
</Row>
</ModalBody>

View File

@ -13,6 +13,7 @@ import JKProfileGenres from './JKProfileGenres';
import JKProfilePerformanceSamples from './JKProfilePerformanceSamples';
import { useAuth } from '../../context/AuthContext';
import JKConnectButton from './JKConnectButton';
import JKMessageButton from './JKMessageButton';
import JKLatencyBadge from './JKLatencyBadge';
import JKLastActiveAgo from './JKLastActiveAgo';
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
</button>
</button> */}
<JKMessageButton currentUser={currentUser} user={user}>
<FontAwesomeIcon icon="comments" transform="shrink-4 down-1" className="mr-1" /> Send Message
</JKMessageButton>
</div>
)}
</div>

View File

@ -1,5 +1,5 @@
import { useEffect } from 'react';
const useScript = (src, onloadHandler) => {
const useScript = (src, onloadHandler = () => {}) => {
useEffect(() => {
const script = document.createElement('script');
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 { Route, Switch, Redirect, NavLink } from 'react-router-dom';
import { Card, CardBody, Row, Col, Button } from 'reactstrap';
import Logo from '../components/navbar/Logo';
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 { Route, Switch } from 'react-router-dom';
import Dashboard from '../components/dashboard/Dashboard';
import DashboardAlt from '../components/dashboard-alt/DashboardAlt';
import NavbarTop from '../components/navbar/NavbarTop';
import NavbarVertical from '../components/navbar/NavbarVertical';
import Footer from '../components/footer/Footer';
import loadable from '@loadable/component';
import AppContext from '../context/Context';
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 { useAuth } from '../context/AuthContext';
import { getCurrentUser } from '../helpers/rest';
const AUTH_STAGES = {
loading: 1,
authenticated: 2,
unauthenticated: 3
};
const DashboardRoutes = loadable(() => import('./DashboardRoutes'));
const DashboardLayout = ({ location }) => {
const { isFluid, isVertical, navbarStyle } = useContext(AppContext);
const { currentUser, setCurrentUser } = useAuth();
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();
}, []);
const isKanban = getPageName('kanban');
useEffect(() => {
DashboardRoutes.preload();
@ -65,84 +27,22 @@ const DashboardLayout = ({ location }) => {
window.scrollTo(0, 0);
}, [location.pathname]);
switch (stage) {
case AUTH_STAGES['authenticated']:
return <DashboardSection />;
case AUTH_STAGES['unauthenticated']:
return <LoginRequestSection />;
default:
return <DashboardLoadingIndicator />;
}
};
const DashboardLoadingIndicator = () => {
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'}>
{isVertical && <NavbarVertical isKanban={isKanban} navbarStyle={navbarStyle} />}
<ProductProvider>
<div className="content">
<NavbarTop />
<Switch>
{/* <Route path="/" exact component={Dashboard} /> */}
{/* <Route path="/dashboard-alt" exact component={DashboardAlt} /> */}
<Route path="/" exact component={JKDashboard} />
<Route path="/" exact component={Dashboard} />
<Route path="/dashboard-alt" exact component={DashboardAlt} />
<DashboardRoutes />
</Switch>
{!isKanban && <Footer />}
</div>
{/* <SidePanelModal path={location.pathname} /> */}
<SidePanelModal path={location.pathname} />
</ProductProvider>
</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 { Redirect, Route, Switch } from 'react-router-dom';
// import Alerts from '../components/bootstrap-components/Alerts';
// import Avatar from '../components/bootstrap-components/Avatar';
// import AutocompleteExample from '../components/bootstrap-components/AutocompleteExample';
// import Backgrounds from '../components/bootstrap-components/Backgrounds';
// import Badges from '../components/bootstrap-components/Badges';
// import Breadcrumbs from '../components/bootstrap-components/Breadcrumb';
// import Buttons from '../components/bootstrap-components/Buttons';
// import Cards from '../components/bootstrap-components/Cards';
// import Carousel from '../components/bootstrap-components/Carousel';
// import Collapses from '../components/bootstrap-components/Collapses';
// import Combo from '../components/bootstrap-components/Combo';
// import CookieNotice from '../components/bootstrap-components/CookieNotice';
// import Dropdowns from '../components/bootstrap-components/Dropdowns';
// import FalconAccordions from '../components/bootstrap-components/FalconAccordions';
// import Forms from '../components/bootstrap-components/Forms';
// import ListGroups from '../components/bootstrap-components/ListGroups';
// import Modals from '../components/bootstrap-components/Modals';
// import Navbars from '../components/bootstrap-components/Navbars';
// import NavBarTop from '../components/bootstrap-components/NavBarTop';
// import Navs from '../components/bootstrap-components/Navs';
// import PageHeaders from '../components/bootstrap-components/PageHeaders';
// import Paginations from '../components/bootstrap-components/Paginations';
// import Popovers from '../components/bootstrap-components/Popovers';
// import ProgressBar from '../components/bootstrap-components/ProgressBar';
// import Sidepanel from '../components/bootstrap-components/Sidepanel';
// import Spinners from '../components/bootstrap-components/Spinners';
// import Tables from '../components/bootstrap-components/Tables';
// import Tabs from '../components/bootstrap-components/Tabs';
// import Tooltips from '../components/bootstrap-components/Tooltips';
// import VerticalNavbar from '../components/bootstrap-components/VerticalNavbar';
// import Calendar from '../components/calendar/Calendar';
// import ChangeLog from '../components/changelog/ChangeLog';
// import Chat from '../components/chat/Chat';
// import GettingStarted from '../components/documentation/GettingStarted';
// import Checkout from '../components/e-commerce/Checkout';
// import Customers from '../components/e-commerce/Customers';
// import FavouriteItems from '../components/e-commerce/FavouriteItems';
// import OrderDetails from '../components/e-commerce/OrderDetails';
// import Orders from '../components/e-commerce/Orders';
// import ProductDetails from '../components/e-commerce/ProductDetails';
// import Products from '../components/e-commerce/Products';
// import ShoppingCart from '../components/e-commerce/ShoppingCart';
// import Compose from '../components/email/Compose';
// import EmailDetail from '../components/email/EmailDetail';
// import Inbox from '../components/email/Inbox';
// import InboxProvider from '../components/email/inbox/InboxProvider';
// import Starter from '../components/extra/Starter';
// import Feed from '../components/feed/Feed';
// import Kanban from '../components/kanban/Kanban';
// import Activity from '../components/page/Activity';
// import Associations from '../components/page/Associations';
// import Billing from '../components/page/Billing';
// import CustomerDetails from '../components/page/CustomerDetails';
// import EventCreate from '../components/page/EventCreate';
// import EventDetail from '../components/page/EventDetail';
// import Events from '../components/page/Events';
// import Faq from '../components/page/Faq';
// import InvitePeople from '../components/page/InvitePeople';
// import Invoice from '../components/page/Invoice';
// import Notifications from '../components/page/Notifications';
// import People from '../components/page/People';
// import Settings from '../components/page/Settings';
// import BulkSelect from '../components/plugins/BulkSelect';
// import CalendarExample from '../components/plugins/CalendarExample';
// import Chart from '../components/plugins/Chart';
// import CodeHighlightDoc from '../components/plugins/CodeHighlightDoc';
// import CountUpExample from '../components/plugins/Countup';
// import DatetimeExample from '../components/plugins/Datetime';
// import Dropzone from '../components/plugins/Dropzone';
// import EchartMap from '../components/plugins/EchartMap';
// import Echarts from '../components/plugins/Echarts';
// import EmojiMart from '../components/plugins/EmojiMart';
// import FontAwesome from '../components/plugins/FontAwesome';
// import GoogleMapExample from '../components/plugins/GoogleMap';
// import ImageLightbox from '../components/plugins/ImageLightbox';
// import Leaflet from '../components/plugins/Leaflet';
// import Lottie from '../components/plugins/Lottie';
// import Plyr from '../components/plugins/Plyr';
// import ProgressBarJs from '../components/plugins/ProgressBarJs';
// import QuillEditorExample from '../components/plugins/Quill';
// import ReactBeautifulDnD from '../components/plugins/ReactBeautifulDnD';
// import ReactBootstrapTable2 from '../components/plugins/ReactBootstrapTable2';
// import ReactHookFrom from '../components/plugins/ReactHookFrom';
// import Scrollbar from '../components/plugins/Scrollbar';
// import Select from '../components/plugins/Select';
// import SlickCarousel from '../components/plugins/SlickCarousel';
// import Toastify from '../components/plugins/Toastify';
// import Typed from '../components/plugins/Typed';
// import Pricing from '../components/pricing/Pricing';
// import PricingAlt from '../components/pricing/PricingAlt';
// import Profile from '../components/profile/Profile';
// import Borders from '../components/utilities/Borders';
// import Clearfix from '../components/utilities/Clearfix';
// import CloseIcon from '../components/utilities/CloseIcon';
// import Colors from '../components/utilities/Colors';
// import Display from '../components/utilities/Display';
// import Embed from '../components/utilities/Embed';
// import Figures from '../components/utilities/Figures';
// import Flex from '../components/utilities/Flex';
// import Grid from '../components/utilities/Grid';
// import Sizing from '../components/utilities/Sizing';
// import Spacing from '../components/utilities/Spacing';
// import StretchedLink from '../components/utilities/StretchedLink';
// import Typography from '../components/utilities/Typography';
// import VerticalAlign from '../components/utilities/VerticalAlign';
// import Visibility from '../components/utilities/Visibility';
// import Widgets from '../components/widgets/Widgets';
import JKPeople from '../components/page/JKPeople';
import Alerts from '../components/bootstrap-components/Alerts';
import Avatar from '../components/bootstrap-components/Avatar';
import AutocompleteExample from '../components/bootstrap-components/AutocompleteExample';
import Backgrounds from '../components/bootstrap-components/Backgrounds';
import Badges from '../components/bootstrap-components/Badges';
import Breadcrumbs from '../components/bootstrap-components/Breadcrumb';
import Buttons from '../components/bootstrap-components/Buttons';
import Cards from '../components/bootstrap-components/Cards';
import Carousel from '../components/bootstrap-components/Carousel';
import Collapses from '../components/bootstrap-components/Collapses';
import Combo from '../components/bootstrap-components/Combo';
import CookieNotice from '../components/bootstrap-components/CookieNotice';
import Dropdowns from '../components/bootstrap-components/Dropdowns';
import FalconAccordions from '../components/bootstrap-components/FalconAccordions';
import Forms from '../components/bootstrap-components/Forms';
import ListGroups from '../components/bootstrap-components/ListGroups';
import Modals from '../components/bootstrap-components/Modals';
import Navbars from '../components/bootstrap-components/Navbars';
import NavBarTop from '../components/bootstrap-components/NavBarTop';
import Navs from '../components/bootstrap-components/Navs';
import PageHeaders from '../components/bootstrap-components/PageHeaders';
import Paginations from '../components/bootstrap-components/Paginations';
import Popovers from '../components/bootstrap-components/Popovers';
import ProgressBar from '../components/bootstrap-components/ProgressBar';
import Sidepanel from '../components/bootstrap-components/Sidepanel';
import Spinners from '../components/bootstrap-components/Spinners';
import Tables from '../components/bootstrap-components/Tables';
import Tabs from '../components/bootstrap-components/Tabs';
import Tooltips from '../components/bootstrap-components/Tooltips';
import VerticalNavbar from '../components/bootstrap-components/VerticalNavbar';
import Calendar from '../components/calendar/Calendar';
import ChangeLog from '../components/changelog/ChangeLog';
import Chat from '../components/chat/Chat';
import GettingStarted from '../components/documentation/GettingStarted';
import Checkout from '../components/e-commerce/Checkout';
import Customers from '../components/e-commerce/Customers';
import FavouriteItems from '../components/e-commerce/FavouriteItems';
import OrderDetails from '../components/e-commerce/OrderDetails';
import Orders from '../components/e-commerce/Orders';
import ProductDetails from '../components/e-commerce/ProductDetails';
import Products from '../components/e-commerce/Products';
import ShoppingCart from '../components/e-commerce/ShoppingCart';
import Compose from '../components/email/Compose';
import EmailDetail from '../components/email/EmailDetail';
import Inbox from '../components/email/Inbox';
import InboxProvider from '../components/email/inbox/InboxProvider';
import Starter from '../components/extra/Starter';
import Feed from '../components/feed/Feed';
import Kanban from '../components/kanban/Kanban';
import Activity from '../components/page/Activity';
import Associations from '../components/page/Associations';
import Billing from '../components/page/Billing';
import CustomerDetails from '../components/page/CustomerDetails';
import EventCreate from '../components/page/EventCreate';
import EventDetail from '../components/page/EventDetail';
import Events from '../components/page/Events';
import Faq from '../components/page/Faq';
import InvitePeople from '../components/page/InvitePeople';
import Invoice from '../components/page/Invoice';
import Notifications from '../components/page/Notifications';
import People from '../components/page/People';
import Settings from '../components/page/Settings';
import BulkSelect from '../components/plugins/BulkSelect';
import CalendarExample from '../components/plugins/CalendarExample';
import Chart from '../components/plugins/Chart';
import CodeHighlightDoc from '../components/plugins/CodeHighlightDoc';
import CountUpExample from '../components/plugins/Countup';
import DatetimeExample from '../components/plugins/Datetime';
import Dropzone from '../components/plugins/Dropzone';
import EchartMap from '../components/plugins/EchartMap';
import Echarts from '../components/plugins/Echarts';
import EmojiMart from '../components/plugins/EmojiMart';
import FontAwesome from '../components/plugins/FontAwesome';
import GoogleMapExample from '../components/plugins/GoogleMap';
import ImageLightbox from '../components/plugins/ImageLightbox';
import Leaflet from '../components/plugins/Leaflet';
import Lottie from '../components/plugins/Lottie';
import Plyr from '../components/plugins/Plyr';
import ProgressBarJs from '../components/plugins/ProgressBarJs';
import QuillEditorExample from '../components/plugins/Quill';
import ReactBeautifulDnD from '../components/plugins/ReactBeautifulDnD';
import ReactBootstrapTable2 from '../components/plugins/ReactBootstrapTable2';
import ReactHookFrom from '../components/plugins/ReactHookFrom';
import Scrollbar from '../components/plugins/Scrollbar';
import Select from '../components/plugins/Select';
import SlickCarousel from '../components/plugins/SlickCarousel';
import Toastify from '../components/plugins/Toastify';
import Typed from '../components/plugins/Typed';
import Pricing from '../components/pricing/Pricing';
import PricingAlt from '../components/pricing/PricingAlt';
import Profile from '../components/profile/Profile';
import Borders from '../components/utilities/Borders';
import Clearfix from '../components/utilities/Clearfix';
import CloseIcon from '../components/utilities/CloseIcon';
import Colors from '../components/utilities/Colors';
import Display from '../components/utilities/Display';
import Embed from '../components/utilities/Embed';
import Figures from '../components/utilities/Figures';
import Flex from '../components/utilities/Flex';
import Grid from '../components/utilities/Grid';
import Sizing from '../components/utilities/Sizing';
import Spacing from '../components/utilities/Spacing';
import StretchedLink from '../components/utilities/StretchedLink';
import Typography from '../components/utilities/Typography';
import VerticalAlign from '../components/utilities/VerticalAlign';
import Visibility from '../components/utilities/Visibility';
import Widgets from '../components/widgets/Widgets';
// const InboxRoutes = ({ match: { url } }) => (
// <InboxProvider>
// <Switch>
// <Route path={`${url}/email-detail`} exact component={EmailDetail} />
// <Route path={`${url}/inbox`} exact component={Inbox} />
// <Route path={`${url}/compose`} exact component={Compose} />
const InboxRoutes = ({ match: { url } }) => (
<InboxProvider>
<Switch>
<Route path={`${url}/email-detail`} exact component={EmailDetail} />
<Route path={`${url}/inbox`} exact component={Inbox} />
<Route path={`${url}/compose`} exact component={Compose} />
// {/*Redirect*/}
// <Redirect to="/errors/404" />
// </Switch>
// </InboxProvider>
// );
{/*Redirect*/}
<Redirect to="/errors/404" />
</Switch>
</InboxProvider>
);
// const ProductRoutes = ({ match: { url } }) => (
// <Switch>
// <Route path={`${url}/products/:productLayout`} exact component={Products} />
// <Route path={`${url}/checkout`} exact component={Checkout} />
// <Route path={`${url}/product-details/:id`} exact component={ProductDetails} />
// <Route path={`${url}/product-details/`} exact component={ProductDetails} />
// <Route path={`${url}/shopping-cart`} exact component={ShoppingCart} />
// <Route path={`${url}/orders`} exact component={Orders} />
// <Route path={`${url}/order-details`} exact component={OrderDetails} />
// <Route path={`${url}/customers`} exact component={Customers} />
// <Route path={`${url}/favourite-items`} exact component={FavouriteItems} />
const ProductRoutes = ({ match: { url } }) => (
<Switch>
<Route path={`${url}/products/:productLayout`} exact component={Products} />
<Route path={`${url}/checkout`} exact component={Checkout} />
<Route path={`${url}/product-details/:id`} exact component={ProductDetails} />
<Route path={`${url}/product-details/`} exact component={ProductDetails} />
<Route path={`${url}/shopping-cart`} exact component={ShoppingCart} />
<Route path={`${url}/orders`} exact component={Orders} />
<Route path={`${url}/order-details`} exact component={OrderDetails} />
<Route path={`${url}/customers`} exact component={Customers} />
<Route path={`${url}/favourite-items`} exact component={FavouriteItems} />
// {/*Redirect*/}
// <Redirect to="/errors/404" />
// </Switch>
// );
{/*Redirect*/}
<Redirect to="/errors/404" />
</Switch>
);
const DashboardRoutes = () => (
<Switch>
<Route path="/friends" component={JKPeople} />
{/* <Route path="/feed" exact component={Feed} /> */}
<Route path="/feed" exact component={Feed} />
{/*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/billing" exact component={Billing} />
<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/profile" exact component={Profile} />
<Route path="/pages/settings" exact component={Settings} />
<Route path="/pages/starter" exact component={Starter} /> */}
<Route path="/pages/starter" exact component={Starter} />
{/*chat*/}
{/* <Route path="/chat" exact component={Chat} /> */}
<Route path="/chat" exact component={Chat} />
{/*calendar*/}
{/* <Route path="/calendar" exact component={Calendar} /> */}
<Route path="/calendar" exact component={Calendar} />
{/*kanban*/}
{/* <Route path="/kanban" exact component={Kanban} /> */}
<Route path="/kanban" exact component={Kanban} />
{/*E commerce*/}
{/* <Route path="/e-commerce" component={ProductRoutes} /> */}
<Route path="/e-commerce" component={ProductRoutes} />
{/*Email*/}
{/* <Route path="/email" component={InboxRoutes} /> */}
<Route path="/email" component={InboxRoutes} />
{/*widgets*/}
{/* <Route path="/widgets" component={Widgets} /> */}
<Route path="/widgets" component={Widgets} />
{/*Documentation*/}
{/* <Route path="/documentation" exact component={GettingStarted} /> */}
<Route path="/documentation" exact component={GettingStarted} />
{/*Changelog*/}
{/* <Route path="/changelog" exact component={ChangeLog} /> */}
<Route path="/changelog" exact component={ChangeLog} />
{/*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/accordions" exact component={FalconAccordions} />
<Route path="/components/avatar" exact component={Avatar} />
@ -215,10 +210,10 @@ const DashboardRoutes = () => (
<Route path="/components/tables" exact component={Tables} />
<Route path="/components/tooltips" exact component={Tooltips} />
<Route path="/components/spinners" exact component={Spinners} />
<Route path="/components/carousel" exact component={Carousel} /> */}
<Route path="/components/carousel" exact component={Carousel} />
{/*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/closeIcon" exact component={CloseIcon} />
<Route path="/utilities/colors" exact component={Colors} />
@ -232,10 +227,10 @@ const DashboardRoutes = () => (
<Route path="/utilities/stretchedLink" exact component={StretchedLink} />
<Route path="/utilities/typography" exact component={Typography} />
<Route path="/utilities/verticalAlign" exact component={VerticalAlign} />
<Route path="/utilities/visibility" exact component={Visibility} /> */}
<Route path="/utilities/visibility" exact component={Visibility} />
{/*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/typed" exact component={Typed} />
<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/emoji-mart" exact component={EmojiMart} />
<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 to="/errors/404" />
</Switch>
);
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 { toast, ToastContainer } from 'react-toastify';
import { CloseButton, Fade } from '../components/common/Toast';
@ -6,42 +6,33 @@ import { CloseButton, Fade } from '../components/common/Toast';
import DashboardLayout from './DashboardLayout';
import ErrorLayout from './ErrorLayout';
// import loadable from '@loadable/component';
//const AuthBasicLayout = loadable(() => import('./AuthBasicLayout'));
//const Landing = loadable(() => import('../components/landing/Landing'));
//const WizardLayout = loadable(() => import('../components/auth/wizard/WizardLayout'));
//const AuthCardRoutes = loadable(() => import('../components/auth/card/AuthCardRoutes'));
//const AuthSplitRoutes = loadable(() => import('../components/auth/split/AuthSplitRoutes'));
import loadable from '@loadable/component';
const AuthBasicLayout = loadable(() => import('./AuthBasicLayout'));
const Landing = loadable(() => import('../components/landing/Landing'));
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 = () => {
useEffect(() => {
//AuthBasicLayout.preload();
//Landing.preload();
//WizardLayout.preload();
//AuthCardRoutes.preload();
//AuthSplitRoutes.preload();
AuthBasicLayout.preload();
Landing.preload();
WizardLayout.preload();
AuthCardRoutes.preload();
AuthSplitRoutes.preload();
}, []);
return (
<Router fallback={<span />}>
<Switch>
{/* <Route path="/friends" exact component={PeopleList} /> */}
{/* <Route path="/landing" exact component={Landing} /> */}
{/* <Route path="/authentication/card" component={AuthCardRoutes} />
<Route path="/landing" exact component={Landing} />
<Route path="/authentication/card" component={AuthCardRoutes} />
<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="/authentication/basic" component={AuthBasicLayout} /> */}
<Route path="/authentication/basic" component={AuthBasicLayout} />
<Route component={DashboardLayout} />
</Switch>
<ToastContainer transition={Fade} closeButton={<CloseButton />} position={toast.POSITION.BOTTOM_LEFT} />
</Router>
);

View File

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

View File

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

View File

@ -985,7 +985,7 @@ module JamRuby
end
# 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(
:photo_url => sender_photo_url,
:sender_name => sender_name,
@ -993,7 +993,8 @@ module JamRuby
:msg => msg,
:clipped_msg => clipped_msg,
:notification_id => notification_id,
:created_at => created_at
:created_at => created_at,
text_message_id: text_message_id
)
Jampb::ClientMessage.new(

View File

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

View File

@ -55,7 +55,7 @@ module JamRuby
tm.save
# 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
end

View File

@ -12,7 +12,8 @@ class ApiTextMessagesController < ApiController
def create
@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

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
child :source_user => :source_user do |msg|
attributes :id, :name, :first_name
attributes :id, :name
end
child :target_user => :target_user do |msg|
attributes :id, :name, :first_name
attributes :id, :name
end