mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
added support for starting channels
This commit is contained in:
parent
e80eb49036
commit
9cad9392be
@ -3426,12 +3426,15 @@ components:
|
|||||||
ChannelParams:
|
ChannelParams:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- subject
|
- dataType
|
||||||
|
- data
|
||||||
- groups
|
- groups
|
||||||
- cards
|
- cards
|
||||||
properties:
|
properties:
|
||||||
subject:
|
dataType:
|
||||||
$ref: '#/components/schemas/Subject'
|
type: string
|
||||||
|
data:
|
||||||
|
type: string
|
||||||
groups:
|
groups:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
@ -9,25 +9,26 @@ import (
|
|||||||
|
|
||||||
func AddChannel(w http.ResponseWriter, r *http.Request) {
|
func AddChannel(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
account, code, err := BearerAppToken(r, false)
|
account, code, err := ParamAgentToken(r, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrResponse(w, code, err)
|
ErrResponse(w, code, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var subject Subject
|
var params ChannelParams
|
||||||
if err := ParseRequest(r, w, &subject); err != nil {
|
if err := ParseRequest(r, w, ¶ms); err != nil {
|
||||||
ErrResponse(w, http.StatusBadRequest, err)
|
ErrResponse(w, http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cards := []*store.Card{}
|
||||||
slot := &store.ChannelSlot{}
|
slot := &store.ChannelSlot{}
|
||||||
err = store.DB.Transaction(func(tx *gorm.DB) error {
|
err = store.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
|
|
||||||
channel := &store.Channel{}
|
channel := &store.Channel{}
|
||||||
channel.AccountID = account.ID
|
channel.AccountID = account.ID
|
||||||
channel.Data = subject.Data
|
channel.Data = params.Data
|
||||||
channel.DataType = subject.DataType
|
channel.DataType = params.DataType
|
||||||
channel.DetailRevision = account.ChannelRevision + 1
|
channel.DetailRevision = account.ChannelRevision + 1
|
||||||
channel.TopicRevision = account.ChannelRevision + 1
|
channel.TopicRevision = account.ChannelRevision + 1
|
||||||
if res := tx.Save(channel).Error; res != nil {
|
if res := tx.Save(channel).Error; res != nil {
|
||||||
@ -42,9 +43,31 @@ func AddChannel(w http.ResponseWriter, r *http.Request) {
|
|||||||
if res := tx.Save(slot).Error; res != nil {
|
if res := tx.Save(slot).Error; res != nil {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
for _, cardId := range params.Cards {
|
||||||
|
cardSlot := store.CardSlot{}
|
||||||
|
if res := tx.Preload("Card").Where("account_id = ? AND card_slot_id = ?", account.ID, cardId).First(&cardSlot).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
if res := tx.Model(&slot.Channel).Association("Cards").Append(cardSlot.Card); res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
cards = append(cards, cardSlot.Card);
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, groupId := range params.Groups {
|
||||||
|
groupSlot := store.GroupSlot{}
|
||||||
|
if res := tx.Preload("Group").Where("account_id = ? AND group_slot_id = ?", account.ID, groupId).First(&groupSlot).Error; res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
if res := tx.Model(&slot.Channel).Association("Groups").Append(groupSlot.Group); res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if res := tx.Model(&account).Update("channel_revision", account.ChannelRevision + 1).Error; res != nil {
|
if res := tx.Model(&account).Update("channel_revision", account.ChannelRevision + 1).Error; res != nil {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -53,6 +76,9 @@ func AddChannel(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetStatus(account)
|
SetStatus(account)
|
||||||
|
for _, card := range cards {
|
||||||
|
SetContactChannelNotification(account, card);
|
||||||
|
}
|
||||||
WriteResponse(w, getChannelModel(slot, true, true))
|
WriteResponse(w, getChannelModel(slot, true, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +200,9 @@ type ChannelMembers struct {
|
|||||||
|
|
||||||
type ChannelParams struct {
|
type ChannelParams struct {
|
||||||
|
|
||||||
Subject *Subject `json:"subject"`
|
DataType string `json:"dataType"`
|
||||||
|
|
||||||
|
Data string `json:"data"`
|
||||||
|
|
||||||
Groups []string `json:"groups"`
|
Groups []string `json:"groups"`
|
||||||
|
|
||||||
|
@ -131,10 +131,6 @@ func TestContactSync(t *testing.T) {
|
|||||||
¶m, nil, APP_TOKENAGENT, set.A.Token, &msg, nil))
|
¶m, nil, APP_TOKENAGENT, set.A.Token, &msg, nil))
|
||||||
assert.NoError(t, ApiTestMsg(SetCloseMessage, "GET", "/contact/closeMessage",
|
assert.NoError(t, ApiTestMsg(SetCloseMessage, "GET", "/contact/closeMessage",
|
||||||
nil, &msg, "", "", nil, nil))
|
nil, &msg, "", "", nil, nil))
|
||||||
param["cardId"] = set.D.A.CardId
|
|
||||||
assert.NoError(t, ApiTestMsg(GetCard, "GET", "/contact/cards/{cardId}",
|
|
||||||
¶m, nil, APP_TOKENAGENT, set.D.Token, card, nil))
|
|
||||||
assert.Nil(t, card.Data)
|
|
||||||
|
|
||||||
// delete card
|
// delete card
|
||||||
param["cardId"] = set.A.C.CardId
|
param["cardId"] = set.A.C.CardId
|
||||||
|
10
net/web/src/Api/addChannel.js
Normal file
10
net/web/src/Api/addChannel.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||||
|
|
||||||
|
export async function addChannel(token, cards, subject, description ) {
|
||||||
|
let data = { subject, description };
|
||||||
|
let params = { dataType: 'superbasic', data: JSON.stringify(data), groups: [], cards };
|
||||||
|
let channel = await fetchWithTimeout(`/content/channels?agent=${token}`, { method: 'POST', body: JSON.stringify(params)} );
|
||||||
|
checkResponse(channel);
|
||||||
|
return await channel.json();
|
||||||
|
}
|
||||||
|
|
@ -95,6 +95,13 @@ export function Contact() {
|
|||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ConfirmConnect = () => {
|
||||||
|
if (state.showButtons.confirmConnect) {
|
||||||
|
return <ProfileButton ghost onClick={() => actions.connect()}>Save & Connect</ProfileButton>
|
||||||
|
}
|
||||||
|
return <></>
|
||||||
|
}
|
||||||
|
|
||||||
const SaveRequest = () => {
|
const SaveRequest = () => {
|
||||||
if (state.showButtons.saveRequest) {
|
if (state.showButtons.saveRequest) {
|
||||||
return <ProfileButton ghost onClick={() => actions.saveConnect()}>Save & Connect</ProfileButton>
|
return <ProfileButton ghost onClick={() => actions.saveConnect()}>Save & Connect</ProfileButton>
|
||||||
@ -130,6 +137,7 @@ export function Contact() {
|
|||||||
<Ignore />
|
<Ignore />
|
||||||
<Deny />
|
<Deny />
|
||||||
<Save />
|
<Save />
|
||||||
|
<ConfirmConnect />
|
||||||
<SaveRequest />
|
<SaveRequest />
|
||||||
<Connect />
|
<Connect />
|
||||||
<Accept />
|
<Accept />
|
||||||
|
@ -182,7 +182,7 @@ export function useContact() {
|
|||||||
}
|
}
|
||||||
if (status === 'pending') {
|
if (status === 'pending') {
|
||||||
updateState({ status: 'pending' });
|
updateState({ status: 'pending' });
|
||||||
updateState({ showButtons: { ignore: true, confirm: true, saveRequest: true }});
|
updateState({ showButtons: { ignore: true, confirm: true, confirmConnect: true }});
|
||||||
}
|
}
|
||||||
if (status === 'confirmed') {
|
if (status === 'confirmed') {
|
||||||
updateState({ status: 'confirmed' });
|
updateState({ status: 'confirmed' });
|
||||||
|
@ -18,6 +18,6 @@ export const ProfileInput = styled(Input)`
|
|||||||
|
|
||||||
export const ProfileSpin = styled(Spin)`
|
export const ProfileSpin = styled(Spin)`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
x-index: 10;
|
z-index: 10;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import { Button, Select, Modal } from 'antd';
|
import { Button, Select, Modal, Collapse, Input } from 'antd';
|
||||||
import { SelectItem } from './AddChannel.styled';
|
import { SelectItem, ConversationWrapper, Description, BusySpin } from './AddChannel.styled';
|
||||||
import { Logo } from '../../../../../Logo/Logo';
|
import { Logo } from '../../../../../Logo/Logo';
|
||||||
|
|
||||||
export function AddChannel({ state, actions }) {
|
export function AddChannel({ state, actions }) {
|
||||||
@ -17,14 +17,24 @@ export function AddChannel({ state, actions }) {
|
|||||||
}, [actions]);
|
}, [actions]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<ConversationWrapper>
|
||||||
<Select
|
<Select
|
||||||
mode="multiple"
|
mode="multiple"
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
placeholder="Select Contacts"
|
placeholder="Select Contacts"
|
||||||
defaultValue={[]}
|
defaultValue={[]}
|
||||||
options={options}
|
options={options}
|
||||||
onChange={(value) => console.log(value)}
|
onChange={(value) => actions.setStartCards(value)}
|
||||||
optionLabelProp="label"
|
optionLabelProp="label"
|
||||||
/>
|
/>
|
||||||
|
<Collapse ghost="true">
|
||||||
|
<Collapse.Panel header="Conversation Details (optional)" key="1">
|
||||||
|
<Input placeholder="Subject" onChange={(e) => actions.setStartSubject(e.target.value)} value={state.startSubject} />
|
||||||
|
<Description placeholder="Description" autoSize={{ minRows: 2, maxRows: 6 }}
|
||||||
|
onChange={(e) => actions.setStartDescription(e.target.value)} value={state.startDescription} />
|
||||||
|
</Collapse.Panel>
|
||||||
|
</Collapse>
|
||||||
|
<BusySpin size="large" spinning={state.busy} />
|
||||||
|
</ConversationWrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
import { Input, Spin } from 'antd';
|
||||||
|
|
||||||
|
export const ConversationWrapper = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
`;
|
||||||
|
|
||||||
export const SelectItem = styled.div`
|
export const SelectItem = styled.div`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -6,3 +13,12 @@ export const SelectItem = styled.div`
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const Description = styled(Input.TextArea)`
|
||||||
|
margin-top: 16px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const BusySpin = styled(Spin)`
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10;
|
||||||
|
`
|
||||||
|
|
||||||
|
@ -8,10 +8,16 @@ export function Channels({ showAdd, setShowAdd }) {
|
|||||||
|
|
||||||
const { state, actions } = useChannels();
|
const { state, actions } = useChannels();
|
||||||
|
|
||||||
|
const onStart = async () => {
|
||||||
|
if (await actions.addChannel()) {
|
||||||
|
setShowAdd(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChannelsWrapper>
|
<ChannelsWrapper>
|
||||||
<Modal title="Start Conversation" visible={showAdd} centered
|
<Modal title="Start Conversation" visible={showAdd} centered
|
||||||
onOk={() => setShowAdd(false)} onCancel={() => setShowAdd(false)}>
|
okText="Start" onOk={() => onStart()} onCancel={() => setShowAdd(false)}>
|
||||||
<AddChannel state={state} actions={actions} />
|
<AddChannel state={state} actions={actions} />
|
||||||
</Modal>
|
</Modal>
|
||||||
</ChannelsWrapper>
|
</ChannelsWrapper>
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
import { useContext, useState, useEffect } from 'react';
|
import { useContext, useState, useEffect } from 'react';
|
||||||
import { AppContext } from '../../../../AppContext/AppContext';
|
import { AppContext } from '../../../../AppContext/AppContext';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { addChannel } from '../../../../Api/addChannel';
|
||||||
|
|
||||||
export function useChannels() {
|
export function useChannels() {
|
||||||
|
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
startCards: [],
|
startCards: [],
|
||||||
|
startSubject: '',
|
||||||
|
startDescription: '',
|
||||||
|
busy: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateState = (value) => {
|
const updateState = (value) => {
|
||||||
@ -19,6 +23,24 @@ export function useChannels() {
|
|||||||
getCardImageUrl: app?.actions?.getCardImageurl,
|
getCardImageUrl: app?.actions?.getCardImageurl,
|
||||||
getCards: app?.actions?.getConnectedCards,
|
getCards: app?.actions?.getConnectedCards,
|
||||||
setStartCards: (cards) => updateState({ startCards: cards }),
|
setStartCards: (cards) => updateState({ startCards: cards }),
|
||||||
|
setStartSubject: (value) => updateState({ startSubject: value }),
|
||||||
|
setStartDescription: (value) => updateState({ startDescription: value }),
|
||||||
|
addChannel: async () => {
|
||||||
|
let done = false;
|
||||||
|
if (!state.busy) {
|
||||||
|
updateState({ busy: true });
|
||||||
|
try {
|
||||||
|
let channel = await addChannel(app.state.token, state.startCards, state.startSubject, state.startDescription);
|
||||||
|
console.log(channel);
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
window.alert(err);
|
||||||
|
}
|
||||||
|
updateState({ busy: false });
|
||||||
|
}
|
||||||
|
return done;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -46,7 +46,7 @@ export function Contacts() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setAddButton(addUser);
|
setAddButton(addConversation);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
Loading…
Reference in New Issue
Block a user