mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
update data modelling for realtime chat app (#630)
This commit is contained in:
parent
30273d354d
commit
ddfd7cd0fe
@ -3,7 +3,7 @@ import { Subscription } from 'react-apollo';
|
||||
import gql from 'graphql-tag';
|
||||
import ChatWrapper from './ChatWrapper';
|
||||
|
||||
const subscribeToEvent = gql`
|
||||
const subscribeToNewMessages = gql`
|
||||
subscription {
|
||||
message ( order_by: id_desc limit: 1) {
|
||||
id
|
||||
@ -14,21 +14,18 @@ const subscribeToEvent = gql`
|
||||
`;
|
||||
|
||||
const emitOnlineEvent = gql`
|
||||
mutation ($userId: Int!){
|
||||
insert_user_online(objects: [
|
||||
{
|
||||
user_id: $userId,
|
||||
mutation ($userId:Int!){
|
||||
update_user (
|
||||
_set: {
|
||||
last_seen: "now()"
|
||||
}
|
||||
],
|
||||
on_conflict: {
|
||||
constraint: user_online_pkey,
|
||||
action: update
|
||||
where: {
|
||||
id: {
|
||||
_eq: $userId
|
||||
}
|
||||
}
|
||||
) {
|
||||
returning {
|
||||
user_id
|
||||
}
|
||||
affected_rows
|
||||
}
|
||||
}
|
||||
`;
|
||||
@ -63,7 +60,7 @@ class Chat extends React.Component {
|
||||
}
|
||||
});
|
||||
},
|
||||
1000
|
||||
3000
|
||||
);
|
||||
}
|
||||
|
||||
@ -77,7 +74,7 @@ class Chat extends React.Component {
|
||||
return (
|
||||
<div>
|
||||
<Subscription
|
||||
subscription={subscribeToEvent}
|
||||
subscription={subscribeToNewMessages}
|
||||
>
|
||||
{
|
||||
({data, error, loading}) => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import RenderMessages from './RenderMessages';
|
||||
import Textbox from './Textbox'
|
||||
import OnlineUsers from './OnlineUsersWrapper';
|
||||
import OnlineUsers from './OnlineUsers';
|
||||
import "../App.css";
|
||||
|
||||
export default class RenderMessagesProxy extends React.Component {
|
||||
|
@ -2,15 +2,14 @@ import React from 'react';
|
||||
import { Subscription } from 'react-apollo';
|
||||
import moment from 'moment';
|
||||
import gql from 'graphql-tag';
|
||||
import UserList from './OnlineUsersList';
|
||||
|
||||
const fetchOnlineUsersSubscription = gql`
|
||||
subscription{
|
||||
subscription {
|
||||
user_online (
|
||||
limit: 1,
|
||||
order_by: last_seen_desc
|
||||
){
|
||||
last_seen
|
||||
order_by: username_asc
|
||||
) {
|
||||
id
|
||||
username
|
||||
}
|
||||
}
|
||||
`;
|
||||
@ -25,16 +24,9 @@ class OnlineUsers extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
setRefetch = (refetch) => {
|
||||
this.setState({
|
||||
...this.state,
|
||||
refetch
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div className="onlineUsers">
|
||||
<Subscription
|
||||
subscription={fetchOnlineUsersSubscription}
|
||||
>
|
||||
@ -44,18 +36,21 @@ class OnlineUsers extends React.Component {
|
||||
return null;
|
||||
}
|
||||
if (error) { return "Error loading online users"; }
|
||||
if (this.state.refetch) {
|
||||
this.state.refetch();
|
||||
}
|
||||
return null;
|
||||
return (
|
||||
<div>
|
||||
<p className="userListHeading"> Online Users ({!data.user_online ? 0 : data.user_online.length})</p>
|
||||
<ul className="userList">
|
||||
{
|
||||
data.user_online.map((u) => {
|
||||
return <li key={u.id}>{u.username}</li>
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
</Subscription>
|
||||
<UserList
|
||||
userId={this.props.userId}
|
||||
refetch={this.state.refetch}
|
||||
setRefetch={this.setRefetch}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Query } from 'react-apollo';
|
||||
import moment from 'moment';
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
const fetchOnlineUsersQuery = gql`
|
||||
query ($timestamp: timestamptz!, $selfId: Int ) {
|
||||
user (
|
||||
where: {
|
||||
online : {
|
||||
last_seen: {
|
||||
_gt: $timestamp
|
||||
}
|
||||
}
|
||||
},
|
||||
order_by: username_asc
|
||||
){
|
||||
id
|
||||
username
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
class UserList extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
time: moment().subtract(10, 'seconds').format(),
|
||||
refetch: null
|
||||
}
|
||||
}
|
||||
|
||||
getQueryVariables() {
|
||||
return {
|
||||
timestamp: moment().subtract(10, 'seconds').format(),
|
||||
selfId: this.props.userId
|
||||
};
|
||||
}
|
||||
|
||||
refetchOnlineUsers = async () => {
|
||||
if (this.state.refetch) {
|
||||
const resp = await this.state.refetch(this.getQueryVariables())
|
||||
if (resp.data) {
|
||||
this.setState({
|
||||
...this.state,
|
||||
users: [ ...resp.data.user]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { users } = this.state;
|
||||
if (this.state.refetch && !this.props.refetch) {
|
||||
this.props.setRefetch(this.refetchOnlineUsers);
|
||||
}
|
||||
return (
|
||||
<div className="onlineUsers">
|
||||
<p className="userListHeading"> Online Users ({!users ? 0 : users.length})</p>
|
||||
<Query
|
||||
query={fetchOnlineUsersQuery}
|
||||
variables={this.getQueryVariables()}
|
||||
>
|
||||
{
|
||||
({data, error, loading, refetch}) => {
|
||||
if (loading) {
|
||||
return null;
|
||||
}
|
||||
if (error) { return "Error loading online users"; }
|
||||
if (!this.state.refetch) {
|
||||
this.setState({
|
||||
...this.state,
|
||||
refetch
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
</Query>
|
||||
<div>
|
||||
<ul className="userList">
|
||||
{ users ?
|
||||
users.map((u) => {
|
||||
return <li key={u.id}>{u.username}</li>
|
||||
}) :
|
||||
null
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default UserList
|
@ -20,21 +20,18 @@ const insertMessage = gql`
|
||||
`;
|
||||
|
||||
const emitTypingEvent = gql`
|
||||
mutation ($userId: Int!){
|
||||
insert_user_typing(objects: [
|
||||
{
|
||||
user_id: $userId,
|
||||
mutation ($userId: Int) {
|
||||
update_user (
|
||||
_set: {
|
||||
last_typed: "now()"
|
||||
}
|
||||
],
|
||||
on_conflict: {
|
||||
constraint: user_typing_pkey,
|
||||
action: update
|
||||
where: {
|
||||
id: {
|
||||
_eq: $userId
|
||||
}
|
||||
}
|
||||
) {
|
||||
returning {
|
||||
user_id
|
||||
}
|
||||
affected_rows
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -1,55 +1,33 @@
|
||||
import React from 'react';
|
||||
import { Subscription } from 'react-apollo';
|
||||
import moment from 'moment';
|
||||
import gql from 'graphql-tag';
|
||||
import '../App.css';
|
||||
|
||||
const getUserTyping = gql`
|
||||
subscription ($timestamp: timestamptz!, $selfId: Int ) {
|
||||
subscription ($selfId: Int ) {
|
||||
user_typing (
|
||||
where: {
|
||||
_and: {
|
||||
last_typed: {
|
||||
_gt: $timestamp
|
||||
},
|
||||
user_id: {
|
||||
_neq: $selfId
|
||||
}
|
||||
id: {
|
||||
_neq: $selfId
|
||||
}
|
||||
},
|
||||
order_by: last_typed_desc,
|
||||
limit: 1
|
||||
order_by: last_typed_desc
|
||||
){
|
||||
user_id
|
||||
last_typed
|
||||
user {
|
||||
username
|
||||
}
|
||||
username
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
class TypingIndicator extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
time: moment().subtract(0.5, 'seconds').format(),
|
||||
}
|
||||
}
|
||||
componentDidMount() {
|
||||
setInterval(
|
||||
() => this.setState({ time: moment().subtract(2, 'seconds').format()}),
|
||||
5000
|
||||
);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div className="typingIndicator">
|
||||
<Subscription
|
||||
subscription={getUserTyping}
|
||||
variables={{
|
||||
timestamp: this.state.time,
|
||||
selfId: this.props.userId
|
||||
}}
|
||||
>
|
||||
@ -57,10 +35,10 @@ class TypingIndicator extends React.Component {
|
||||
({ data, loading, error}) => {
|
||||
if (loading) { return ""; }
|
||||
if (error) { return ""; }
|
||||
if (data.user_typing.length === 0 || data.user_id === this.props.userId ) {
|
||||
if (data.user_typing.length === 0) {
|
||||
return "";
|
||||
} else {
|
||||
return `${data.user_typing[0].user.username} is typing ...`;
|
||||
return `${data.user_typing[0].username} is typing ...`;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -68,26 +46,7 @@ class TypingIndicator extends React.Component {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export default TypingIndicator;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user