mirror of
https://github.com/balzack/databag.git
synced 2025-03-13 00:50:03 +00:00
more webapp conversation refactor
This commit is contained in:
parent
ba279dfcda
commit
3ceea69f99
@ -5,6 +5,7 @@ import { useAdmin } from './useAdmin.hook';
|
||||
|
||||
export function Admin() {
|
||||
|
||||
const [ modal, modalContext ] = Modal.useModal();
|
||||
const { state, actions } = useAdmin();
|
||||
|
||||
const login = async () => {
|
||||
@ -12,9 +13,10 @@ export function Admin() {
|
||||
await actions.login();
|
||||
}
|
||||
catch(err) {
|
||||
Modal.error({
|
||||
modal.error({
|
||||
title: 'Login Error',
|
||||
content: 'Please confirm your password.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -27,6 +29,7 @@ export function Admin() {
|
||||
|
||||
return (
|
||||
<AdminWrapper>
|
||||
{ modalContext }
|
||||
<div className="app-title">
|
||||
<span>Databag</span>
|
||||
<div className="settings" onClick={() => actions.navUser()}>
|
||||
|
@ -5,6 +5,7 @@ import { useCreateAccount } from './useCreateAccount.hook';
|
||||
|
||||
export function CreateAccount() {
|
||||
|
||||
const [ modal, modalContext ] = Modal.useModal();
|
||||
const { state, actions } = useCreateAccount();
|
||||
|
||||
const create = async () => {
|
||||
@ -12,9 +13,10 @@ export function CreateAccount() {
|
||||
await actions.onCreateAccount();
|
||||
}
|
||||
catch(err) {
|
||||
Modal.error({
|
||||
modal.error({
|
||||
title: 'Create Account Error',
|
||||
content: 'Please check with you administrator.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -27,6 +29,7 @@ export function CreateAccount() {
|
||||
|
||||
return (
|
||||
<CreateAccountWrapper>
|
||||
{ modalContext }
|
||||
<div className="app-title">
|
||||
<span>Databag</span>
|
||||
<div className="settings" onClick={() => actions.onSettings()}>
|
||||
|
@ -5,6 +5,7 @@ import { useLogin } from './useLogin.hook';
|
||||
|
||||
export function Login() {
|
||||
|
||||
const [ modal, modalContext ] = Modal.useModal();
|
||||
const { state, actions } = useLogin();
|
||||
|
||||
const login = async () => {
|
||||
@ -12,9 +13,10 @@ export function Login() {
|
||||
await actions.onLogin();
|
||||
}
|
||||
catch(err) {
|
||||
Modal.error({
|
||||
modal.error({
|
||||
title: 'Login Error',
|
||||
content: 'Please confirm your username and password.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -27,6 +29,7 @@ export function Login() {
|
||||
|
||||
return (
|
||||
<LoginWrapper>
|
||||
{ modalContext }
|
||||
<div className="app-title">
|
||||
<span>Databag</span>
|
||||
<div className="settings" onClick={() => actions.onSettings()}>
|
||||
|
@ -8,6 +8,7 @@ export function useConversationContext() {
|
||||
const [state, setState] = useState({
|
||||
offsync: false,
|
||||
topics: new Map(),
|
||||
card: null,
|
||||
channel: null,
|
||||
topicRevision: null,
|
||||
});
|
||||
@ -92,7 +93,7 @@ export function useConversationContext() {
|
||||
else {
|
||||
await channel.actions.addTopic(channelId, type, message, files);
|
||||
}
|
||||
await resync();
|
||||
resync();
|
||||
};
|
||||
|
||||
const removeTopic = async (cardId, channelId, topicId) => {
|
||||
@ -115,7 +116,7 @@ export function useConversationContext() {
|
||||
await resync();
|
||||
};
|
||||
|
||||
const getTopicAssetUrl = async (cardId, channelId, topicId, assetId) => {
|
||||
const getTopicAssetUrl = (cardId, channelId, topicId, assetId) => {
|
||||
if (cardId) {
|
||||
return card.actions.getTopicAssetUrl(cardId, channelId, topicId, assetId);
|
||||
}
|
||||
@ -183,8 +184,9 @@ export function useConversationContext() {
|
||||
// sync channel details
|
||||
if (setDetailRevision.current !== detailRevision) {
|
||||
let channelSync;
|
||||
let cardSync;
|
||||
if (cardId) {
|
||||
const cardSync = card.state.cards.get(cardId);
|
||||
cardSync = card.state.cards.get(cardId);
|
||||
channelSync = cardSync?.channels.get(channelId);
|
||||
}
|
||||
else {
|
||||
@ -192,7 +194,7 @@ export function useConversationContext() {
|
||||
}
|
||||
if (channelSync) {
|
||||
setDetailRevision.current = detailRevision;
|
||||
updateState({ channel: channelSync });
|
||||
updateState({ card: cardSync, channel: channelSync });
|
||||
}
|
||||
else {
|
||||
syncing.current = false;
|
||||
@ -310,7 +312,7 @@ export function useConversationContext() {
|
||||
const { cardId, channelId } = conversationId.current;
|
||||
await setTopicSubject(cardId, channelId, type, subject);
|
||||
},
|
||||
getTopicAssetUrl: (topicId, assetId) => {
|
||||
getTopicAssetUrl: (assetId, topicId) => {
|
||||
const { cardId, channelId } = conversationId.current;
|
||||
return getTopicAssetUrl(cardId, channelId, topicId, assetId);
|
||||
},
|
||||
|
@ -101,7 +101,7 @@ export function Dashboard() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Modal title="Settings" visible={state.showSettings} centered
|
||||
<Modal title="Settings" visible={state.showSettings} centered bodyStyle={{ padding: 16 }}
|
||||
okText="Save" onOk={() => actions.setSettings()} onCancel={() => actions.setShowSettings(false)}>
|
||||
<SettingsLayout direction="vertical">
|
||||
<div className="field">
|
||||
@ -144,7 +144,7 @@ export function Dashboard() {
|
||||
</div>
|
||||
</SettingsLayout>
|
||||
</Modal>
|
||||
<Modal title="Create Account" visible={state.showCreate} centered width="fitContent"
|
||||
<Modal bodyStyle={{ padding: 16 }} title="Create Account" visible={state.showCreate} centered width="fitContent"
|
||||
footer={[ <Button type="primary" onClick={() => actions.setShowCreate(false)}>OK</Button> ]}
|
||||
onCancel={() => actions.setShowCreate(false)}>
|
||||
<CreateLayout>
|
||||
|
@ -6,12 +6,14 @@ import { Modal, Tooltip, Button } from 'antd';
|
||||
|
||||
export function AccountItem({ item, remove }) {
|
||||
|
||||
const [ modal, modalContext ] = Modal.useModal();
|
||||
const { state, actions } = useAccountItem(item, remove);
|
||||
|
||||
const removeAccount = () => {
|
||||
Modal.confirm({
|
||||
modal.confirm({
|
||||
title: 'Are you sure you want to delete the account?',
|
||||
icon: <ExclamationCircleOutlined />,
|
||||
bodyStyle: { padding: 16 },
|
||||
onOk() {
|
||||
applyRemoveAccount();
|
||||
},
|
||||
@ -24,9 +26,10 @@ export function AccountItem({ item, remove }) {
|
||||
await actions.remove();
|
||||
}
|
||||
catch(err) {
|
||||
Modal.error({
|
||||
modal.error({
|
||||
title: 'Failed to Remove Account',
|
||||
content: 'Please try again.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -36,9 +39,10 @@ export function AccountItem({ item, remove }) {
|
||||
await actions.setStatus(status);
|
||||
}
|
||||
catch(err) {
|
||||
Modal.error({
|
||||
modal.error({
|
||||
title: 'Failed to Set Account Status',
|
||||
content: 'Please try again.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -48,9 +52,10 @@ export function AccountItem({ item, remove }) {
|
||||
await actions.setAccessLink();
|
||||
}
|
||||
catch(err) {
|
||||
Modal.error({
|
||||
modal.error({
|
||||
title: 'Failed to Set Account Access',
|
||||
content: 'Please try again.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -65,6 +70,7 @@ export function AccountItem({ item, remove }) {
|
||||
|
||||
return (
|
||||
<AccountItemWrapper>
|
||||
{ modalContext }
|
||||
<div className="avatar">
|
||||
<Logo url={state.imageUrl} width={32} height={32} radius={4} />
|
||||
</div>
|
||||
@ -116,7 +122,7 @@ export function AccountItem({ item, remove }) {
|
||||
</div>
|
||||
<Modal title="Access Account" visible={state.showAccess} centered width="fitContent"
|
||||
footer={[ <Button type="primary" onClick={() => actions.setShowAccess(false)}>OK</Button> ]}
|
||||
onCancel={() => actions.setShowAccess(false)}>
|
||||
bodyStyle={{ padding: 16 }} onCancel={() => actions.setShowAccess(false)}>
|
||||
<AccessLayout>
|
||||
<div className="url">
|
||||
<div className="label">Browser Link:</div>
|
||||
|
@ -1,3 +1,17 @@
|
||||
.ant-modal-content {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.ant-modal-title {
|
||||
padding-top: 16px !important;
|
||||
padding-left: 16px !important;
|
||||
}
|
||||
|
||||
.ant-modal-footer {
|
||||
padding-right: 16px !important;
|
||||
padding-bottom: 16px !important;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
|
@ -31,6 +31,7 @@ export function Profile({ closeProfile }) {
|
||||
modal.error({
|
||||
title: 'Failed to Save',
|
||||
content: 'Please try again.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -45,6 +46,7 @@ export function Profile({ closeProfile }) {
|
||||
modal.error({
|
||||
title: 'Failed to Save',
|
||||
content: 'Please try again.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -53,6 +55,7 @@ export function Profile({ closeProfile }) {
|
||||
modal.confirm({
|
||||
title: 'Are you sure you want to logout?',
|
||||
icon: <LogoutOutlined />,
|
||||
bodyStyle: { padding: 16 },
|
||||
onOk() {
|
||||
actions.logout();
|
||||
},
|
||||
@ -155,7 +158,7 @@ export function Profile({ closeProfile }) {
|
||||
</div>
|
||||
)}
|
||||
<Modal title="Profile Image" centered visible={state.editProfileImage} footer={editImageFooter}
|
||||
onCancel={actions.clearEditProfileImage}>
|
||||
style={{ padding: 16 }} onCancel={actions.clearEditProfileImage}>
|
||||
|
||||
<ProfileImageWrapper>
|
||||
<Cropper image={state.editImage} crop={state.crop} zoom={state.zoom} aspect={1}
|
||||
@ -164,7 +167,7 @@ export function Profile({ closeProfile }) {
|
||||
|
||||
</Modal>
|
||||
<Modal title="Profile Details" centered visible={state.editProfileDetails} footer={editDetailsFooter}
|
||||
onCancel={actions.clearEditProfileDetails}>
|
||||
style={{ padding: 16 }} onCancel={actions.clearEditProfileDetails}>
|
||||
|
||||
<ProfileDetailsWrapper>
|
||||
<div class="info">
|
||||
|
@ -18,6 +18,7 @@ export function AccountAccess() {
|
||||
modal.error({
|
||||
title: 'Failed to Set Sealing Key',
|
||||
comment: 'Please try again.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -31,6 +32,7 @@ export function AccountAccess() {
|
||||
modal.error({
|
||||
title: 'Update Registry Failed',
|
||||
content: 'Please try again.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -45,6 +47,7 @@ export function AccountAccess() {
|
||||
modal.error({
|
||||
title: 'Failed to Save',
|
||||
comment: 'Please try again.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ export function Channels({ open, active }) {
|
||||
<Button type="primary" icon={<CommentOutlined />} onClick={actions.setShowAdd}>New Topic</Button>
|
||||
</div>
|
||||
)}
|
||||
<Modal title="New Topic" centered visible={state.showAdd} footer={null} destroyOnClose={true}
|
||||
<Modal bodyStyle={{ padding: 16 }} title="New Topic" centered visible={state.showAdd} footer={null} destroyOnClose={true}
|
||||
onCancel={actions.clearShowAdd}>
|
||||
<AddChannel added={added} cancelled={actions.clearShowAdd} />
|
||||
</Modal>
|
||||
|
@ -18,6 +18,7 @@ export function AddChannel({ added, cancelled }) {
|
||||
modal.error({
|
||||
title: 'Failed to Create Topic',
|
||||
content: 'Please try again.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import { Logo } from 'logo/Logo';
|
||||
import { AddTopic } from './addTopic/AddTopic';
|
||||
import { TopicItem } from './topicItem/TopicItem';
|
||||
import { List, Spin, Tooltip } from 'antd';
|
||||
import { ChannelHeader } from './channelHeader/ChannelHeader';
|
||||
|
||||
export function Conversation({ closeConversation, openDetails, cardId, channelId }) {
|
||||
|
||||
@ -38,36 +39,7 @@ export function Conversation({ closeConversation, openDetails, cardId, channelId
|
||||
|
||||
return (
|
||||
<ConversationWrapper>
|
||||
<div class="header">
|
||||
<div class="title">
|
||||
<div class="logo">
|
||||
<Logo img={state.logoImg} url={state.logoUrl} width={32} height={32} radius={4} />
|
||||
</div>
|
||||
<div class="label">{ state.subject }</div>
|
||||
{ state.error && state.display === 'small' && (
|
||||
<StatusError onClick={actions.resync}>
|
||||
<ExclamationCircleOutlined />
|
||||
</StatusError>
|
||||
)}
|
||||
{ state.error && state.display !== 'small' && (
|
||||
<Tooltip placement="bottom" title="sync error">
|
||||
<StatusError onClick={actions.resync}>
|
||||
<ExclamationCircleOutlined />
|
||||
</StatusError>
|
||||
</Tooltip>
|
||||
)}
|
||||
{ state.display !== 'xlarge' && (
|
||||
<div class="button" onClick={openDetails}>
|
||||
<SettingOutlined />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{ state.display !== 'xlarge' && (
|
||||
<div class="button" onClick={closeConversation}>
|
||||
<CloseOutlined />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<ChannelHeader openDetails={openDetails} closeConversation={closeConversation} contentKey={state.contentKey}/>
|
||||
<div class="thread" ref={thread} onScroll={scrollThread}>
|
||||
{ state.delayed && state.topics.length === 0 && (
|
||||
<div class="empty">This Topic Has No Messages</div>
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { TopicItemWrapper } from './TopicItem.styled';
|
||||
import { useTopicItem } from './useTopicItem.hook';
|
||||
import { VideoAsset } from './videoAsset/VideoAsset';
|
||||
import { AudioAsset } from './audioAsset/AudioAsset';
|
||||
import { ImageAsset } from './imageAsset/ImageAsset';
|
||||
@ -10,6 +9,21 @@ import { Carousel } from 'carousel/Carousel';
|
||||
|
||||
export function TopicItem({ host, topic }) {
|
||||
|
||||
const renderAsset = (asset, idx) => {
|
||||
if (asset.image) {
|
||||
return <ImageAsset thumbUrl={topic.assetUrl(asset.image.thumb, topic.id)}
|
||||
fullUrl={topic.assetUrl(asset.image.full, topic.id)} />
|
||||
}
|
||||
if (asset.video) {
|
||||
return <VideoAsset thumbUrl={topic.assetUrl(asset.video.thumb, topic.id)}
|
||||
lqUrl={topic.assetUrl(asset.video.lq, topic.id)} hdUrl={topic.assetUrl(asset.video.hd, topic.id)} />
|
||||
}
|
||||
if (asset.audio) {
|
||||
return <AudioAsset label={asset.audio.label} audioUrl={topic.assetUrl(asset.audio.full, topic.id)} />
|
||||
}
|
||||
return <></>
|
||||
}
|
||||
|
||||
return (
|
||||
<TopicItemWrapper>
|
||||
<div class="topic-header">
|
||||
@ -21,9 +35,37 @@ export function TopicItem({ host, topic }) {
|
||||
<div>{ topic.createdStr }</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="message">
|
||||
<div style={{ color: topic.textColor, fontSize: topic.textSize }}>{ topic.text }</div>
|
||||
</div>
|
||||
{ topic.status !== 'confirmed' && (
|
||||
<div class="skeleton">
|
||||
<Skeleton size={'small'} active={true} title={false} />
|
||||
</div>
|
||||
)}
|
||||
{ topic.status === 'confirmed' && (
|
||||
<>
|
||||
{ topic.assets?.length && (
|
||||
<>
|
||||
{ topic.transform === 'error' && (
|
||||
<div class="asset-placeholder">
|
||||
<FireOutlined style={{ fontSize: 32, color: '#ff8888' }} />
|
||||
</div>
|
||||
)}
|
||||
{ topic.transform === 'incomplete' && (
|
||||
<div class="asset-placeholder">
|
||||
<PictureOutlined style={{ fontSize: 32 }} />
|
||||
</div>
|
||||
)}
|
||||
{ topic.transform === 'complete' && (
|
||||
<div class="topic-assets">
|
||||
<Carousel pad={40} items={topic.assets} itemRenderer={renderAsset} />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<div class="message">
|
||||
<div style={{ color: topic.textColor, fontSize: topic.textSize }}>{ topic.text }</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</TopicItemWrapper>
|
||||
)
|
||||
}
|
||||
|
@ -1,169 +0,0 @@
|
||||
import { useContext, useState, useEffect, useRef } from 'react';
|
||||
import { ConversationContext } from 'context/ConversationContext';
|
||||
import { ProfileContext } from 'context/ProfileContext';
|
||||
import { CardContext } from 'context/CardContext';
|
||||
import { getProfileByGuid } from 'context/cardUtil';
|
||||
|
||||
export function useTopicItem(topic, sealed, sealKey) {
|
||||
|
||||
const [state, setState] = useState({
|
||||
init: false,
|
||||
name: null,
|
||||
handle: null,
|
||||
imageUrl: null,
|
||||
text: null,
|
||||
created: null,
|
||||
confirmed: false,
|
||||
ready: false,
|
||||
error: false,
|
||||
owner: false,
|
||||
assets: [],
|
||||
topicId: null,
|
||||
editing: false,
|
||||
busy: false,
|
||||
textColor: '#444444',
|
||||
textSize: 14,
|
||||
});
|
||||
|
||||
const profile = useContext(ProfileContext);
|
||||
const card = useContext(CardContext);
|
||||
const conversation = useContext(ConversationContext);
|
||||
const editMessage = useRef(null);
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
let owner = false;
|
||||
if (profile.state.identity.guid === topic?.data?.topicDetail.guid) {
|
||||
owner = true;
|
||||
}
|
||||
|
||||
let text = null;
|
||||
let textColor = '#444444';
|
||||
let textSize = 14;
|
||||
|
||||
if (!topic?.data) {
|
||||
console.log("invalid topic:", topic);
|
||||
return;
|
||||
}
|
||||
|
||||
const { status, transform, data, dataType } = topic.data.topicDetail;
|
||||
let message;
|
||||
let sealed = false;
|
||||
let ready = false;
|
||||
let error = false;
|
||||
let confirmed = false;
|
||||
let assets = [];
|
||||
if (status === 'confirmed') {
|
||||
confirmed = true;
|
||||
if (dataType === 'superbasictopic') {
|
||||
try {
|
||||
message = JSON.parse(data);
|
||||
if (typeof message.text === 'string') {
|
||||
text = message.text;
|
||||
}
|
||||
if (message.textColor != null) {
|
||||
textColor = message.textColor;
|
||||
}
|
||||
if (message.textSize != null) {
|
||||
textSize = message.textSize;
|
||||
}
|
||||
if (message.assets) {
|
||||
assets = message.assets;
|
||||
delete message.assets;
|
||||
}
|
||||
if (transform === 'complete') {
|
||||
ready = true;
|
||||
}
|
||||
if (transform === 'error') {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
else if (dataType === 'sealedtopic') {
|
||||
if (topic.data.unsealedMessage) {
|
||||
text = topic.data.unsealedMessage.message?.text;
|
||||
sealed = false;
|
||||
}
|
||||
else {
|
||||
if (sealKey) {
|
||||
conversation.actions.unsealTopic(topic.id, sealKey);
|
||||
}
|
||||
sealed = true;
|
||||
}
|
||||
ready = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (profile.state.identity?.guid) {
|
||||
const { guid, created } = topic.data.topicDetail;
|
||||
|
||||
let createdStr;
|
||||
const date = new Date(created * 1000);
|
||||
const now = new Date();
|
||||
const offset = now.getTime() - date.getTime();
|
||||
if(offset < 86400000) {
|
||||
createdStr = date.toLocaleTimeString([], {hour: 'numeric', minute:'2-digit'});
|
||||
}
|
||||
else if (offset < 31449600000) {
|
||||
createdStr = date.toLocaleDateString("en-US", {day: 'numeric', month:'numeric'});
|
||||
}
|
||||
else {
|
||||
createdStr = date.toLocaleDateString("en-US");
|
||||
}
|
||||
|
||||
if (profile.state.identity.guid === guid) {
|
||||
const { name, handle } = profile.state.identity;
|
||||
const imageUrl = profile.state.imageUrl;
|
||||
updateState({ sealed, name, handle, imageUrl, status, text, transform, assets, confirmed, error, ready, created: createdStr, owner, textColor, textSize, topicId: topic.id, init: true });
|
||||
}
|
||||
else {
|
||||
const { cardId, name, handle, imageSet } = getProfileByGuid(card.state.cards, guid);
|
||||
const imageUrl = imageSet ? card.actions.getCardImageUrl(cardId) : null;
|
||||
updateState({ sealed, name, handle, imageUrl, status, text, transform, assets, confirmed, error, ready, created: createdStr, owner, textColor, textSize, topicId: topic.id, init: true });
|
||||
}
|
||||
}
|
||||
}, [profile, card, conversation, topic, sealKey]);
|
||||
|
||||
const actions = {
|
||||
getAssetUrl: (assetId, topicId) => {
|
||||
return conversation.actions.getAssetUrl(state.topicId, assetId);
|
||||
},
|
||||
removeTopic: async () => {
|
||||
return await conversation.actions.removeTopic(topic.id);
|
||||
},
|
||||
setEditing: (editing) => {
|
||||
editMessage.current = state.message?.text;
|
||||
updateState({ editing });
|
||||
},
|
||||
setEdit: (edit) => {
|
||||
editMessage.current = edit;
|
||||
},
|
||||
setMessage: async () => {
|
||||
if (!state.busy) {
|
||||
updateState({ busy: true });
|
||||
try {
|
||||
if (sealed) {
|
||||
await conversation.actions.setSealedTopicSubject(topic.id, {...state.message, text: editMessage.current }, sealKey);
|
||||
}
|
||||
else {
|
||||
await conversation.actions.setTopicSubject(topic.id,
|
||||
{ ...state.message, text: editMessage.current, assets: state.assets });
|
||||
}
|
||||
updateState({ editing: false });
|
||||
}
|
||||
catch (err) {
|
||||
window.alert(err);
|
||||
}
|
||||
updateState({ busy: false });
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return { state, actions };
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Modal } from 'antd';
|
||||
import ReactResizeDetector from 'react-resize-detector';
|
||||
import { VideoCameraOutlined } from '@ant-design/icons';
|
||||
@ -10,6 +10,10 @@ export function VideoAsset({ thumbUrl, lqUrl, hdUrl }) {
|
||||
const { state, actions } = useVideoAsset();
|
||||
const [dimension, setDimension] = useState({ width: 0, height: 0 });
|
||||
|
||||
useEffect(() => {
|
||||
console.log(dimension);
|
||||
}, [dimension]);
|
||||
|
||||
const activate = () => {
|
||||
if (dimension.width / dimension.height > window.innerWidth / window.innerHeight) {
|
||||
let width = Math.floor(window.innerWidth * 8 / 10);
|
||||
@ -39,7 +43,7 @@ export function VideoAsset({ thumbUrl, lqUrl, hdUrl }) {
|
||||
<VideoCameraOutlined style={{ fontSize: 32, color: '#eeeeee', cursor: 'pointer' }} />
|
||||
</div>
|
||||
)}
|
||||
<Modal centered={true} visible={state.active} width={state.width + 12} bodyStyle={{ paddingBottom: 0, paddingTop: 6, paddingLeft: 6, paddingRight: 6, backgroundColor: '#dddddd' }} footer={null} destroyOnClose={true} closable={false} onCancel={actions.clearActive}>
|
||||
<Modal centered={true} style={{ backgroundColor: '#aacc00', padding: 0 }} visible={state.active} width={state.width + 12} bodyStyle={{ paddingBottom: 0, paddingTop: 6, paddingLeft: 6, paddingRight: 6, backgroundColor: '#dddddd', margin: 0 }} footer={null} destroyOnClose={true} closable={false} onCancel={actions.clearActive}>
|
||||
<video autoplay="true" controls src={hdUrl} width={state.width} height={state.height}
|
||||
playsinline="true" />
|
||||
</Modal>
|
||||
|
@ -106,8 +106,8 @@ export function useConversation(cardId, channelId) {
|
||||
const { card, channel } = conversationId.current;
|
||||
loading.current = true;
|
||||
conversationId.current = null;
|
||||
updateState({ loading: true });
|
||||
await conversation.setChannel(card, channel);
|
||||
updateState({ loading: true, contentKey: null });
|
||||
await conversation.actions.setChannel(card, channel);
|
||||
updateState({ loading: false });
|
||||
loading.current = false;
|
||||
await setChannel();
|
||||
@ -115,7 +115,8 @@ export function useConversation(cardId, channelId) {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
conversation.actions.setChannel(cardId, channelId);
|
||||
conversationId.current = { card: cardId, channel: channelId };
|
||||
setChannel();
|
||||
// eslint-disable-next-line
|
||||
}, [cardId, channelId]);
|
||||
|
||||
@ -175,6 +176,7 @@ export function useConversation(cardId, channelId) {
|
||||
if (item.revision !== revision) {
|
||||
try {
|
||||
const message = JSON.parse(detail.data);
|
||||
item.assets = message.assets;
|
||||
item.text = message.text;
|
||||
item.textColor = message.textColor ? message.textColor : '#444444';
|
||||
item.textSize = message.textSize ? message.textSize : 14;
|
||||
@ -189,6 +191,7 @@ export function useConversation(cardId, channelId) {
|
||||
item.contentKey = state.contentKey;
|
||||
try {
|
||||
const subject = decryptTopicSubject(detail.data, state.contentKey);
|
||||
item.assets = subject.message.assets;
|
||||
item.text = subject.message.text;
|
||||
item.textColor = subject.message.textColor ? subject.message.textColor : '#444444';
|
||||
item.textSize = subject.message.textSize ? subject.message.textSize : 14;
|
||||
@ -198,18 +201,21 @@ export function useConversation(cardId, channelId) {
|
||||
}
|
||||
}
|
||||
}
|
||||
item.transform = detail.transform;
|
||||
item.status = detail.status;
|
||||
item.assetUrl = conversation.actions.getTopicAssetUrl;
|
||||
item.revision = revision;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const messages = new Map();
|
||||
conversation.state.topics.forEach((value, topicId) => {
|
||||
let item = topics.current.get(topicId);
|
||||
conversation.state.topics.forEach((value, id) => {
|
||||
let item = topics.current.get(id);
|
||||
if (!item) {
|
||||
item = { topicId };
|
||||
item = { id };
|
||||
}
|
||||
syncTopic(item, value);
|
||||
messages.set(topicId, item);
|
||||
messages.set(id, item);
|
||||
});
|
||||
topics.current = messages;
|
||||
|
||||
|
@ -18,6 +18,7 @@ export function Details({ cardId, channelId, closeDetails, closeConversation, op
|
||||
modal.confirm({
|
||||
title: 'Are you sure you want to delete the topic?',
|
||||
icon: <ExclamationCircleOutlined />,
|
||||
bodyStyle: { padding: 16 },
|
||||
okText: "Yes, Delete",
|
||||
cancelText: "No, Cancel",
|
||||
onOk() {
|
||||
@ -36,6 +37,7 @@ export function Details({ cardId, channelId, closeDetails, closeConversation, op
|
||||
modal.error({
|
||||
title: 'Failed to Delete Topic',
|
||||
content: 'Please try again.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -44,6 +46,7 @@ export function Details({ cardId, channelId, closeDetails, closeConversation, op
|
||||
modal.confirm({
|
||||
title: 'Are you sure you want to leave the topic?',
|
||||
icon: <ExclamationCircleOutlined />,
|
||||
bodyStyle: { padding: 16 },
|
||||
okText: "Yes, Leave",
|
||||
cancelText: "No, Cancel",
|
||||
onOk() {
|
||||
@ -62,6 +65,7 @@ export function Details({ cardId, channelId, closeDetails, closeConversation, op
|
||||
modal.error({
|
||||
title: 'Failed to Leave Topic',
|
||||
content: 'Please try again.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -75,6 +79,7 @@ export function Details({ cardId, channelId, closeDetails, closeConversation, op
|
||||
modal.error({
|
||||
title: 'Failed to Update Subject',
|
||||
content: 'Please try again.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -88,10 +88,15 @@ export function useDetails(cardId, channelId) {
|
||||
else {
|
||||
locked = false;
|
||||
editable = (chan.cardId == null);
|
||||
const parsed = JSON.parse(chan.data.channelDetail.data);
|
||||
if (parsed.subject) {
|
||||
subject = parsed.subject;
|
||||
subjectUpdate = subject;
|
||||
try {
|
||||
const parsed = JSON.parse(chan.data.channelDetail.data);
|
||||
if (parsed.subject) {
|
||||
subject = parsed.subject;
|
||||
subjectUpdate = subject;
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
const date = new Date(chan.data.channelDetail.created * 1000);
|
||||
|
@ -13,6 +13,7 @@ export function Identity({ openAccount, openCards, cardUpdated }) {
|
||||
modal.confirm({
|
||||
title: 'Are you sure you want to logout?',
|
||||
icon: <LogoutOutlined />,
|
||||
bodyStyle: { padding: 16 },
|
||||
onOk() {
|
||||
actions.logout();
|
||||
},
|
||||
|
@ -18,6 +18,7 @@ export function Listing({ closeListing, openContact }) {
|
||||
modal.error({
|
||||
title: 'Communication Error',
|
||||
content: 'Please confirm your server name.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user