BOD-14 Functional 2 way messaging from app.
This commit is contained in:
@@ -25,17 +25,17 @@ export default class AppContainer extends Component {
|
||||
uri: process.env.REACT_APP_GRAPHQL_ENDPOINT_WS,
|
||||
options: {
|
||||
//lazy: true,
|
||||
reconnect: true
|
||||
// connectionParams: () => {
|
||||
// const token = localStorage.getItem("token");
|
||||
// if (token) {
|
||||
// return {
|
||||
// headers: {
|
||||
// authorization: token ? `Bearer ${token}` : ""
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
reconnect: true,
|
||||
connectionParams: () => {
|
||||
const token = localStorage.getItem("token");
|
||||
if (token) {
|
||||
return {
|
||||
headers: {
|
||||
authorization: token ? `Bearer ${token}` : ""
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
const subscriptionMiddleware = {
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import { ShrinkOutlined } from "@ant-design/icons";
|
||||
import { Avatar, Badge, Col, List, Row } from "antd";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { openConversation, toggleChatVisible } from "../../redux/messaging/messaging.actions";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
});
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
toggleChatVisible: () => dispatch(toggleChatVisible()),
|
||||
openConversation: number => dispatch(openConversation(number))
|
||||
});
|
||||
|
||||
export function ChatConversationListComponent({
|
||||
toggleChatVisible,
|
||||
conversationList,
|
||||
openConversation
|
||||
}) {
|
||||
console.log("conversationList", conversationList);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Row>
|
||||
<Col span={12}>Title</Col>
|
||||
<Col span={2} offset={10}>
|
||||
<ShrinkOutlined onClick={() => toggleChatVisible()} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<List
|
||||
dataSource={conversationList}
|
||||
renderItem={item => (
|
||||
<Badge count={item.messages_aggregate.aggregate.count || 0}>
|
||||
<List.Item
|
||||
key={item.id}
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() =>
|
||||
openConversation({ phone_num: item.phone_num, id: item.id })
|
||||
}>
|
||||
<List.Item.Meta
|
||||
avatar={
|
||||
<Avatar src='https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png' />
|
||||
}
|
||||
title={item.phone_num}
|
||||
description='Some sort of RO info? '
|
||||
/>
|
||||
</List.Item>
|
||||
</Badge>
|
||||
)}
|
||||
/>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ChatConversationListComponent);
|
||||
@@ -0,0 +1,16 @@
|
||||
import React from "react";
|
||||
import ChatConversationListComponent from "./chat-conversation-list.component";
|
||||
import { useSubscription } from "@apollo/react-hooks";
|
||||
import { CONVERSATION_LIST_SUBSCRIPTION } from "../../graphql/conversations.queries";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
|
||||
export default function ChatConversationListContainer() {
|
||||
const { loading, error, data } = useSubscription(
|
||||
CONVERSATION_LIST_SUBSCRIPTION
|
||||
);
|
||||
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type='error' />;
|
||||
return <ChatConversationListComponent conversationList={data.conversations || []} />;
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
import { Button } from "antd";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { closeConversation, sendMessage, toggleConversationVisible } from "../../redux/messaging/messaging.actions";
|
||||
import {
|
||||
closeConversation,
|
||||
sendMessage,
|
||||
toggleConversationVisible
|
||||
} from "../../redux/messaging/messaging.actions";
|
||||
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
@@ -18,13 +22,13 @@ function ChatConversationClosedComponent({
|
||||
}) {
|
||||
return (
|
||||
<div style={{ display: "flex" }}>
|
||||
<div onClick={() => toggleConversationVisible(conversation.phone)}>
|
||||
<PhoneFormatter>{conversation.phone}</PhoneFormatter>
|
||||
<div onClick={() => toggleConversationVisible(conversation.phone_num)}>
|
||||
<PhoneFormatter>{conversation.phone_num}</PhoneFormatter>
|
||||
</div>
|
||||
<Button
|
||||
type='dashed'
|
||||
shape='circle-outline'
|
||||
onClick={() => closeConversation(conversation.phone)}>
|
||||
onClick={() => closeConversation(conversation.phone_num)}>
|
||||
X
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Button, Card } from "antd";
|
||||
import { Button, Card, Badge } from "antd";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
@@ -25,24 +25,26 @@ const mapDispatchToProps = dispatch => ({
|
||||
export function ChatConversationComponent({
|
||||
conversation,
|
||||
toggleConversationVisible,
|
||||
closeConversation
|
||||
closeConversation,
|
||||
messages,
|
||||
subState
|
||||
}) {
|
||||
const messages = [];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Badge count={messages.length}>
|
||||
<Card
|
||||
title={
|
||||
conversation.open ? (
|
||||
<div style={{ display: "flex" }}>
|
||||
<div
|
||||
onClick={() => toggleConversationVisible(conversation.phone)}>
|
||||
<PhoneFormatter>{conversation.phone}</PhoneFormatter>
|
||||
onClick={() =>
|
||||
toggleConversationVisible(conversation.phone_num)
|
||||
}>
|
||||
<PhoneFormatter>{conversation.phone_num}</PhoneFormatter>
|
||||
</div>
|
||||
<Button
|
||||
type='danger'
|
||||
shape='circle-outline'
|
||||
onClick={() => closeConversation(conversation.phone)}>
|
||||
onClick={() => closeConversation(conversation.phone_num)}>
|
||||
X
|
||||
</Button>
|
||||
</div>
|
||||
@@ -57,12 +59,13 @@ export function ChatConversationComponent({
|
||||
<ChatConversationOpenComponent
|
||||
messages={messages}
|
||||
conversation={conversation}
|
||||
subState={subState}
|
||||
/>
|
||||
) : (
|
||||
<ChatConversationClosedComponent conversation={conversation} />
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,33 @@
|
||||
import { useSubscription } from "@apollo/react-hooks";
|
||||
import React from "react";
|
||||
import ChatConversationComponent from "./chat-conversation.component";
|
||||
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { MESSAGES_SUBSCRIPTION } from "../../graphql/messages.queries";
|
||||
import ChatConversationComponent from "./chat-conversation.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
});
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
|
||||
export function ChatConversationContainer({ conversation }) {
|
||||
console.log("conversation", conversation);
|
||||
const { loading, error, data } = useSubscription(MESSAGES_SUBSCRIPTION, {
|
||||
variables: { conversationId: conversation.id }
|
||||
});
|
||||
|
||||
return (
|
||||
<ChatConversationComponent
|
||||
subState={[loading, error]}
|
||||
conversation={conversation}
|
||||
messages={(data && data.messages) || []}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(function ChatConversationContainer({ conversation }) {
|
||||
return <ChatConversationComponent conversation={conversation} />;
|
||||
});
|
||||
)(ChatConversationContainer);
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import React from "react";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import ChatSendMessage from "../chat-send-message/chat-send-message.component";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
|
||||
export default function ChatConversationOpenComponent({
|
||||
conversation,
|
||||
messages
|
||||
messages,
|
||||
subState
|
||||
}) {
|
||||
if (!!!messages) return <div>No Messages</div>;
|
||||
const [loading, error] = subState;
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type='error' />;
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -12,11 +18,13 @@ export default function ChatConversationOpenComponent({
|
||||
<ul>
|
||||
{messages.map(item => (
|
||||
<li
|
||||
key={item.sid}
|
||||
className={`${
|
||||
item.direction === "inbound" ? "sent" : "replies"
|
||||
}`}>
|
||||
<p> {item.body}</p>
|
||||
key={item.id}
|
||||
className={`${item.isoutbound ? "replies" : "sent"}`}>
|
||||
<div>
|
||||
<p>
|
||||
{item.text} <br /> <i>{item.status}</i>
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
@@ -2,6 +2,8 @@ import { Badge, Card } from "antd";
|
||||
import { MessageFilled } from "@ant-design/icons";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ChatConversationListContainer from "../chat-conversation-list/chat-conversation-list.container";
|
||||
|
||||
export default function ChatWindowComponent({
|
||||
chatVisible,
|
||||
toggleChatVisible
|
||||
@@ -11,19 +13,19 @@ export default function ChatWindowComponent({
|
||||
<div>
|
||||
<Badge count={5}>
|
||||
<Card
|
||||
onClick={() => toggleChatVisible()}
|
||||
style={{
|
||||
width: chatVisible ? "300px" : "125px",
|
||||
margin: "0px 10px"
|
||||
}}
|
||||
size="small"
|
||||
>
|
||||
size='small'>
|
||||
{chatVisible ? (
|
||||
<div className="messages" style={{ height: "400px" }}>
|
||||
List of chats here.
|
||||
<div className='messages' style={{ height: "400px" }}>
|
||||
<ChatConversationListContainer />
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<div
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() => toggleChatVisible()}>
|
||||
<MessageFilled />
|
||||
<strong style={{ paddingLeft: "10px" }}>
|
||||
{t("messaging.labels.messaging")}
|
||||
|
||||
@@ -12,19 +12,17 @@ import ChatOverlayComponent from "./chat-overlay.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
chatVisible: selectChatVisible,
|
||||
conversations: selectConversations
|
||||
activeConversations: selectConversations
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
toggleChatVisible: () => dispatch(toggleChatVisible())
|
||||
});
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(function ChatWindowContainer({
|
||||
|
||||
export function ChatOverlayContainer({
|
||||
chatVisible,
|
||||
toggleChatVisible,
|
||||
conversations
|
||||
activeConversations
|
||||
}) {
|
||||
return (
|
||||
<Affix offsetBottom={0}>
|
||||
@@ -35,14 +33,20 @@ export default connect(
|
||||
toggleChatVisible={toggleChatVisible}
|
||||
/>
|
||||
</Badge>
|
||||
{conversations
|
||||
? conversations.map((conversation, idx) => (
|
||||
<Badge key={idx} count={5}>
|
||||
<ChatConversationContainer conversation={conversation} />
|
||||
</Badge>
|
||||
{activeConversations
|
||||
? activeConversations.map(conversation => (
|
||||
<ChatConversationContainer
|
||||
conversation={conversation}
|
||||
key={conversation.id}
|
||||
/>
|
||||
))
|
||||
: null}
|
||||
</div>
|
||||
</Affix>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ChatOverlayContainer);
|
||||
|
||||
@@ -19,11 +19,12 @@ function ChatSendMessageComponent({ conversation, bodyshop, sendMessage }) {
|
||||
|
||||
const handleEnter = () => {
|
||||
sendMessage({
|
||||
to: conversation.phone,
|
||||
to: conversation.phone_num,
|
||||
body: message,
|
||||
messagingServiceSid: bodyshop.messagingservicesid,
|
||||
conversationid: conversation.id
|
||||
});
|
||||
setMessage("");
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -31,6 +32,7 @@ function ChatSendMessageComponent({ conversation, bodyshop, sendMessage }) {
|
||||
<Input.TextArea
|
||||
allowClear
|
||||
autoSize={{ minRows: 1, maxRows: 4 }}
|
||||
value={message}
|
||||
placeholder={t("messaging.labels.typeamessage")}
|
||||
// enterButton={}
|
||||
onChange={e => setMessage(e.target.value)}
|
||||
|
||||
@@ -9,7 +9,9 @@ const errorLink = onError(
|
||||
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
|
||||
)
|
||||
);
|
||||
if (networkError) console.log(`[Network error]: ${networkError}`);
|
||||
if (networkError)
|
||||
console.log(`[Network error]: ${JSON.stringify(networkError)}`);
|
||||
console.log(operation.getContext());
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
15
client/src/graphql/conversations.queries.js
Normal file
15
client/src/graphql/conversations.queries.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { gql } from "apollo-boost";
|
||||
|
||||
export const CONVERSATION_LIST_SUBSCRIPTION = gql`
|
||||
subscription CONVERSATION_LIST_SUBSCRIPTION {
|
||||
conversations {
|
||||
phone_num
|
||||
id
|
||||
messages_aggregate(where: { read: { _eq: false } }) {
|
||||
aggregate {
|
||||
count
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
13
client/src/graphql/messages.queries.js
Normal file
13
client/src/graphql/messages.queries.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import { gql } from "apollo-boost";
|
||||
|
||||
export const MESSAGES_SUBSCRIPTION = gql`
|
||||
subscription MESSAGES_SUBSCRIPTION($conversationId: uuid!) {
|
||||
messages(where: { conversationid: { _eq: $conversationId } }) {
|
||||
text
|
||||
created_at
|
||||
id
|
||||
status
|
||||
isoutbound
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -2,18 +2,20 @@ import MessagingActionTypes from "./messaging.types";
|
||||
|
||||
const INITIAL_STATE = {
|
||||
visible: false,
|
||||
unread: 0,
|
||||
conversations: [
|
||||
{
|
||||
phone: "6049992002",
|
||||
phone_num: "6049992002",
|
||||
id: "519ba10d-6467-4fa5-9c22-59ae891edeb6",
|
||||
open: false
|
||||
},
|
||||
{
|
||||
phone: "6049992991",
|
||||
phone_num: "6049992991",
|
||||
id: "ab57deba-eeb9-40db-b5ae-23f3ce8d7c7b",
|
||||
open: false
|
||||
}
|
||||
]
|
||||
],
|
||||
error: null
|
||||
};
|
||||
|
||||
const messagingReducer = (state = INITIAL_STATE, action) => {
|
||||
@@ -29,11 +31,13 @@ const messagingReducer = (state = INITIAL_STATE, action) => {
|
||||
visible: true
|
||||
};
|
||||
case MessagingActionTypes.OPEN_CONVERSATION:
|
||||
if (state.conversations.find(c => c.phone === action.payload))
|
||||
if (
|
||||
state.conversations.find(c => c.phone_num === action.payload.phone_num)
|
||||
)
|
||||
return {
|
||||
...state,
|
||||
conversations: state.conversations.map(c =>
|
||||
c.phone === action.payload ? { ...c, open: true } : c
|
||||
c.phone_num === action.payload.phone_num ? { ...c, open: true } : c
|
||||
)
|
||||
};
|
||||
else
|
||||
@@ -41,23 +45,29 @@ const messagingReducer = (state = INITIAL_STATE, action) => {
|
||||
...state,
|
||||
conversations: [
|
||||
...state.conversations,
|
||||
{ phone: action.payload, open: true }
|
||||
{
|
||||
phone_num: action.payload.phone_num,
|
||||
id: action.payload.id,
|
||||
open: true
|
||||
}
|
||||
]
|
||||
};
|
||||
case MessagingActionTypes.CLOSE_CONVERSATION:
|
||||
return {
|
||||
...state,
|
||||
conversations: state.conversations.filter(
|
||||
c => c.phone !== action.payload
|
||||
c => c.phone_num !== action.payload
|
||||
)
|
||||
};
|
||||
case MessagingActionTypes.TOGGLE_CONVERSATION_VISIBLE:
|
||||
return {
|
||||
...state,
|
||||
conversations: state.conversations.map(c =>
|
||||
c.phone === action.payload ? { ...c, open: !c.open } : c
|
||||
c.phone_num === action.payload ? { ...c, open: !c.open } : c
|
||||
)
|
||||
};
|
||||
case MessagingActionTypes.SEND_MESSAGE_FAILURE:
|
||||
return { ...state, error: action.payload };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: ALTER TABLE "public"."messages" DROP COLUMN "read";
|
||||
type: run_sql
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: ALTER TABLE "public"."messages" ADD COLUMN "read" boolean NOT NULL DEFAULT
|
||||
false;
|
||||
type: run_sql
|
||||
@@ -0,0 +1,38 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: messages
|
||||
schema: public
|
||||
type: drop_insert_permission
|
||||
- args:
|
||||
permission:
|
||||
check:
|
||||
conversation:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
columns:
|
||||
- id
|
||||
- created_at
|
||||
- updated_at
|
||||
- msid
|
||||
- conversationid
|
||||
- text
|
||||
- image
|
||||
- image_path
|
||||
- isoutbound
|
||||
- status
|
||||
localPresets:
|
||||
- key: ""
|
||||
value: ""
|
||||
set: {}
|
||||
role: user
|
||||
table:
|
||||
name: messages
|
||||
schema: public
|
||||
type: create_insert_permission
|
||||
@@ -0,0 +1,39 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: messages
|
||||
schema: public
|
||||
type: drop_insert_permission
|
||||
- args:
|
||||
permission:
|
||||
check:
|
||||
conversation:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
columns:
|
||||
- id
|
||||
- created_at
|
||||
- updated_at
|
||||
- msid
|
||||
- conversationid
|
||||
- text
|
||||
- image
|
||||
- image_path
|
||||
- isoutbound
|
||||
- status
|
||||
- read
|
||||
localPresets:
|
||||
- key: ""
|
||||
value: ""
|
||||
set: {}
|
||||
role: user
|
||||
table:
|
||||
name: messages
|
||||
schema: public
|
||||
type: create_insert_permission
|
||||
@@ -0,0 +1,36 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: messages
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: false
|
||||
columns:
|
||||
- conversationid
|
||||
- created_at
|
||||
- id
|
||||
- image
|
||||
- image_path
|
||||
- isoutbound
|
||||
- msid
|
||||
- status
|
||||
- text
|
||||
- updated_at
|
||||
computed_fields: []
|
||||
filter:
|
||||
conversation:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
role: user
|
||||
table:
|
||||
name: messages
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -0,0 +1,37 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: messages
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: false
|
||||
columns:
|
||||
- image
|
||||
- isoutbound
|
||||
- read
|
||||
- image_path
|
||||
- msid
|
||||
- status
|
||||
- text
|
||||
- created_at
|
||||
- updated_at
|
||||
- conversationid
|
||||
- id
|
||||
computed_fields: []
|
||||
filter:
|
||||
conversation:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
role: user
|
||||
table:
|
||||
name: messages
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -0,0 +1,38 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: messages
|
||||
schema: public
|
||||
type: drop_update_permission
|
||||
- args:
|
||||
permission:
|
||||
columns:
|
||||
- image
|
||||
- isoutbound
|
||||
- image_path
|
||||
- msid
|
||||
- status
|
||||
- text
|
||||
- created_at
|
||||
- updated_at
|
||||
- conversationid
|
||||
- id
|
||||
filter:
|
||||
conversation:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
localPresets:
|
||||
- key: ""
|
||||
value: ""
|
||||
set: {}
|
||||
role: user
|
||||
table:
|
||||
name: messages
|
||||
schema: public
|
||||
type: create_update_permission
|
||||
@@ -0,0 +1,39 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: messages
|
||||
schema: public
|
||||
type: drop_update_permission
|
||||
- args:
|
||||
permission:
|
||||
columns:
|
||||
- image
|
||||
- isoutbound
|
||||
- read
|
||||
- image_path
|
||||
- msid
|
||||
- status
|
||||
- text
|
||||
- created_at
|
||||
- updated_at
|
||||
- conversationid
|
||||
- id
|
||||
filter:
|
||||
conversation:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
localPresets:
|
||||
- key: ""
|
||||
value: ""
|
||||
set: {}
|
||||
role: user
|
||||
table:
|
||||
name: messages
|
||||
schema: public
|
||||
type: create_update_permission
|
||||
@@ -0,0 +1,37 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: messages
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: false
|
||||
columns:
|
||||
- image
|
||||
- isoutbound
|
||||
- read
|
||||
- image_path
|
||||
- msid
|
||||
- status
|
||||
- text
|
||||
- created_at
|
||||
- updated_at
|
||||
- conversationid
|
||||
- id
|
||||
computed_fields: []
|
||||
filter:
|
||||
conversation:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
role: user
|
||||
table:
|
||||
name: messages
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -0,0 +1,37 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: messages
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: true
|
||||
columns:
|
||||
- image
|
||||
- isoutbound
|
||||
- read
|
||||
- image_path
|
||||
- msid
|
||||
- status
|
||||
- text
|
||||
- created_at
|
||||
- updated_at
|
||||
- conversationid
|
||||
- id
|
||||
computed_fields: []
|
||||
filter:
|
||||
conversation:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
role: user
|
||||
table:
|
||||
name: messages
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -0,0 +1,30 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: conversations
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: false
|
||||
columns:
|
||||
- phone_num
|
||||
- created_at
|
||||
- updated_at
|
||||
- bodyshopid
|
||||
- id
|
||||
computed_fields: []
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
role: user
|
||||
table:
|
||||
name: conversations
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -0,0 +1,30 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: conversations
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: true
|
||||
columns:
|
||||
- phone_num
|
||||
- created_at
|
||||
- updated_at
|
||||
- bodyshopid
|
||||
- id
|
||||
computed_fields: []
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
role: user
|
||||
table:
|
||||
name: conversations
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
Reference in New Issue
Block a user