Merge branch 'messages_overhaul' into staging_environment
This commit is contained in:
commit
4871100365
15 changed files with 339 additions and 106 deletions
|
|
@ -12,7 +12,7 @@ import { useTeamAPI } from "providers";
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
|
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) => ({
|
const useStyles = makeStyles<Theme>((theme: Theme) => ({
|
||||||
button: {
|
button: {
|
||||||
color: getSignatureAccentColour(),
|
color: getSignatureAccentColour(),
|
||||||
width: theme.spacing(6),
|
width: theme.spacing(6),
|
||||||
|
|
@ -70,8 +70,8 @@ export default function HeaderButtons(props: Props) {
|
||||||
setHasNewChats(true);
|
setHasNewChats(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log(team.preferences.chatViewedTimestamp)
|
// console.log(team.preferences.chatViewedTimestamp)
|
||||||
console.log(team.settings.lastChatTimestamp)
|
// console.log(team.settings.lastChatTimestamp)
|
||||||
let viewMoment = moment(team.preferences.chatViewedTimestamp);
|
let viewMoment = moment(team.preferences.chatViewedTimestamp);
|
||||||
let chatMoment = moment(team.settings.lastChatTimestamp);
|
let chatMoment = moment(team.settings.lastChatTimestamp);
|
||||||
if (viewMoment.diff(chatMoment) < 0) {
|
if (viewMoment.diff(chatMoment) < 0) {
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import { AppThemeProvider } from 'theme/AppThemeProvider'
|
||||||
import HTTPProvider from 'providers/http'
|
import HTTPProvider from 'providers/http'
|
||||||
import { Crisp } from "crisp-sdk-web";
|
import { Crisp } from "crisp-sdk-web";
|
||||||
import { useMobile, useSnackbar } from 'hooks'
|
import { useMobile, useSnackbar } from 'hooks'
|
||||||
|
import { initCrisp } from '../chat/CrispChat'
|
||||||
// import FirmwareLoader from './FirmwareLoader'
|
// import FirmwareLoader from './FirmwareLoader'
|
||||||
|
|
||||||
const reducer = (state: GlobalState, action: GlobalStateAction): GlobalState => {
|
const reducer = (state: GlobalState, action: GlobalStateAction): GlobalState => {
|
||||||
|
|
@ -113,20 +114,14 @@ export default function UserWrapper(props: Props) {
|
||||||
}, [setGlobal])
|
}, [setGlobal])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!crispInitialized.current && global?.user) {
|
if (global?.user) {
|
||||||
Crisp.configure(import.meta.env.VITE_CRISP_WEBSITE_ID);
|
initCrisp({
|
||||||
crispInitialized.current = true;
|
websiteId: import.meta.env.VITE_CRISP_WEBSITE_ID,
|
||||||
Crisp.session.reset();
|
email: global.user.settings.email,
|
||||||
Crisp.user.setEmail(global?.user.settings.email);
|
nickname: global.user.settings.name || global.user.settings.email,
|
||||||
// Optional: Set nickname or other info
|
phone: global.user.settings.phoneNumber,
|
||||||
Crisp.user.setNickname(global?.user.settings.name || global?.user.settings.email);
|
tokenId: global.user.id(),
|
||||||
Crisp.user.setPhone(global?.user.settings.phoneNumber);
|
});
|
||||||
|
|
||||||
// For extra security (marks email as verified, prevents spoofing):
|
|
||||||
// Crisp.user.setEmail(user.email, "your-hmac-signature-here"); // See Crisp docs for signing
|
|
||||||
|
|
||||||
// Optional: For session continuity across devices/browsers
|
|
||||||
Crisp.setTokenId(global?.user.id()); // e.g., your DB user ID
|
|
||||||
}
|
}
|
||||||
}, [global]);
|
}, [global]);
|
||||||
|
|
||||||
|
|
@ -162,10 +157,7 @@ export default function UserWrapper(props: Props) {
|
||||||
document.head.appendChild(style);
|
document.head.appendChild(style);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(isMobile)
|
|
||||||
|
|
||||||
if (isMobile) {
|
if (isMobile) {
|
||||||
console.log("isMobile")
|
|
||||||
style.textContent = `
|
style.textContent = `
|
||||||
#crisp-chatbox [aria-label="Open chat"] {
|
#crisp-chatbox [aria-label="Open chat"] {
|
||||||
bottom: 6em !important;
|
bottom: 6em !important;
|
||||||
|
|
|
||||||
BIN
src/assets/common/robotIconDark.png
Normal file
BIN
src/assets/common/robotIconDark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.5 KiB |
BIN
src/assets/common/robotIconLight.png
Normal file
BIN
src/assets/common/robotIconLight.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
|
|
@ -37,6 +37,7 @@ export default function Chat(props: Props) {
|
||||||
|
|
||||||
const loadChats = () => {
|
const loadChats = () => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
|
// console.log("listing chats?")
|
||||||
noteAPI.listChats(10, chats.length, "desc", "timestamp", objectKey).then(resp => {
|
noteAPI.listChats(10, chats.length, "desc", "timestamp", objectKey).then(resp => {
|
||||||
setChats(resp.data.chats ? resp.data.chats.reverse().concat(chats) : [])
|
setChats(resp.data.chats ? resp.data.chats.reverse().concat(chats) : [])
|
||||||
setTotalMessages(resp.data.total)
|
setTotalMessages(resp.data.total)
|
||||||
|
|
@ -76,33 +77,42 @@ export default function Chat(props: Props) {
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadChats()
|
setChats([]);
|
||||||
}, []);
|
setLoaded(false);
|
||||||
|
setLoading(false);
|
||||||
|
setTotalMessages(0);
|
||||||
|
}, [objectKey]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (chats.length === 0 && !loaded) {
|
||||||
|
loadChats();
|
||||||
|
}
|
||||||
|
}, [objectKey, chats, loaded]);
|
||||||
|
|
||||||
const loadMore = () => {
|
const loadMore = () => {
|
||||||
loadChats();
|
loadChats();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<Box className={classes.chatContainer}>
|
||||||
|
<Box sx={{ flex: 1, overflowY: "hidden", minHeight: 0 }}>
|
||||||
{loading && !loaded ? (
|
{loading && !loaded ? (
|
||||||
<Box width="100%" height="100%" alignContent={"center"} textAlign={"center"} >
|
<Box width="100%" height="100%" alignContent="center" textAlign="center">
|
||||||
<CircularProgress />
|
<CircularProgress />
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<Box className={classes.chatContainer}>
|
|
||||||
<ChatOutput
|
<ChatOutput
|
||||||
totalMessages={totalMessages}
|
totalMessages={totalMessages}
|
||||||
messages={chats}
|
messages={chats}
|
||||||
removeNoteMethod={removeNote}
|
removeNoteMethod={removeNote}
|
||||||
loadMore={loadMore}
|
loadMore={loadMore}
|
||||||
/>
|
/>
|
||||||
<Box style={{bottom: 0}}>
|
)}
|
||||||
|
</Box>
|
||||||
|
<Box style={{ flexShrink: 0 }}>
|
||||||
<Divider />
|
<Divider />
|
||||||
<ChatInput newNoteMethod={showNewNotes} objectKey={objectKey} type={type} />
|
<ChatInput newNoteMethod={showNewNotes} objectKey={objectKey} type={type} />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,19 @@
|
||||||
import { ChevronRight } from "@mui/icons-material";
|
import { ChevronRight } from "@mui/icons-material";
|
||||||
import { Box, Drawer, IconButton, Theme, Typography } from "@mui/material";
|
import { Avatar, Box, Divider, Drawer, IconButton, Theme, Tooltip, Typography } from "@mui/material";
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
import { useMobile } from "hooks";
|
import { useMobile } from "hooks";
|
||||||
import { Team } from "models";
|
import { Team } from "models";
|
||||||
import Chat from "./Chat";
|
import Chat from "./Chat";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { useTeamAPI } from "providers";
|
||||||
|
import { openCrispChat } from './CrispChat';
|
||||||
|
import RobotIcon from "products/CommonIcons/robotIcon";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) => {
|
const useStyles = makeStyles<Theme>((theme: Theme) => ({
|
||||||
return ({
|
|
||||||
chatDrawer: {
|
chatDrawer: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column", // Arrange children vertically
|
flexDirection: "column",
|
||||||
backgroundColor: theme.palette.background.default,
|
backgroundColor: theme.palette.background.default,
|
||||||
height: "100%",
|
height: "100%",
|
||||||
maxHeight: "100%",
|
maxHeight: "100%",
|
||||||
|
|
@ -24,18 +27,19 @@ const useStyles = makeStyles((theme: Theme) => {
|
||||||
},
|
},
|
||||||
chatDrawerMobile: {
|
chatDrawerMobile: {
|
||||||
backgroundColor: theme.palette.background.default,
|
backgroundColor: theme.palette.background.default,
|
||||||
height: "auto",
|
height: "100vh",
|
||||||
width: "100%"
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
},
|
},
|
||||||
drawerHeader: {
|
drawerHeader: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
padding: theme.spacing(1),
|
padding: theme.spacing(1),
|
||||||
...theme.mixins.toolbar,
|
...theme.mixins.toolbar,
|
||||||
justifyContent: "flex-start"
|
justifyContent: "flex-start",
|
||||||
}
|
},
|
||||||
});
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
|
@ -46,21 +50,97 @@ interface Props {
|
||||||
export function ChatDrawer(props: Props) {
|
export function ChatDrawer(props: Props) {
|
||||||
const { open, onClose, team } = props;
|
const { open, onClose, team } = props;
|
||||||
const isMobile = useMobile();
|
const isMobile = useMobile();
|
||||||
const classes = useStyles()
|
const classes = useStyles();
|
||||||
|
const teamAPI = useTeamAPI();
|
||||||
|
|
||||||
|
const [selectedTeam, setSelectedTeam] = useState<Team>(team);
|
||||||
|
const [teams, setTeams] = useState<pond.Team[]>([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
teamAPI.listTeams(10, 0, "desc", "name", undefined, false, undefined).then(resp => {
|
||||||
|
setTeams(resp.data.teams)
|
||||||
|
})
|
||||||
|
}, [teamAPI])
|
||||||
|
|
||||||
|
const openCrisp = () => {
|
||||||
|
openCrispChat()
|
||||||
|
onClose()
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer open={open} onClose={onClose} anchor="right" >
|
<Drawer
|
||||||
|
open={open}
|
||||||
|
onClose={onClose}
|
||||||
|
anchor="right"
|
||||||
|
slotProps={{
|
||||||
|
paper: {
|
||||||
|
sx: isMobile ? { width: "100%" } : undefined,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box display="flex" flexDirection="row" height="100%">
|
||||||
|
{/* Side icon column */}
|
||||||
|
<Box
|
||||||
|
display="flex"
|
||||||
|
flexDirection="column"
|
||||||
|
alignItems="center"
|
||||||
|
padding={1}
|
||||||
|
gap={1}
|
||||||
|
sx={(theme: Theme) => ({
|
||||||
|
backgroundColor: theme.palette.background.paper,
|
||||||
|
borderRight: `1px solid ${theme.palette.divider}`,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Tooltip title={team.name()} placement="right">
|
||||||
|
<IconButton
|
||||||
|
onClick={() => setSelectedTeam(team)}
|
||||||
|
sx={{
|
||||||
|
border: selectedTeam.settings?.key === team.settings.key ? "1px solid white" : "1px solid transparent",
|
||||||
|
borderRadius: "50%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Avatar src={team.settings.avatar} />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title={"Chat Assistant"} placement="right">
|
||||||
|
<IconButton
|
||||||
|
onClick={openCrisp}
|
||||||
|
>
|
||||||
|
<RobotIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
<Box width={"100%"} borderBottom={"1px solid grey"} />
|
||||||
|
{teams.map((t, i)=> {
|
||||||
|
if (t.settings?.key === team.key()) return null;
|
||||||
|
return (
|
||||||
|
<Tooltip title={t.settings?.name} key={"chat-team-"+i} placement="right">
|
||||||
|
<IconButton
|
||||||
|
onClick={() => setSelectedTeam(Team.create(t))}
|
||||||
|
sx={{
|
||||||
|
border: selectedTeam.key() === t.settings?.key ? "1px solid white" : "1px solid transparent",
|
||||||
|
borderRadius: "50%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Avatar src={t.settings?.avatar} />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Main chat area */}
|
||||||
<Box className={isMobile ? classes.chatDrawerMobile : classes.chatDrawer}>
|
<Box className={isMobile ? classes.chatDrawerMobile : classes.chatDrawer}>
|
||||||
<Box className={classes.drawerHeader}>
|
<Box className={classes.drawerHeader}>
|
||||||
<IconButton onClick={onClose}>
|
<IconButton onClick={onClose}>
|
||||||
<ChevronRight />
|
<ChevronRight />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Typography>{team.name()} Chat</Typography>
|
<Typography>{selectedTeam.name()} Chat</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Box className={classes.chatContainer}>
|
<Box className={classes.chatContainer}>
|
||||||
<Chat objectKey={team.settings.key} type={pond.NoteType.NOTE_TYPE_TEAM}/>
|
<Chat objectKey={selectedTeam.key()} type={pond.NoteType.NOTE_TYPE_TEAM} />
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -74,10 +74,23 @@ export default function ChatMessage(props: Props) {
|
||||||
const mappedPerm = pond.Permission[perm as keyof typeof pond.Permission];
|
const mappedPerm = pond.Permission[perm as keyof typeof pond.Permission];
|
||||||
return mappedPerm; // Return null for invalid keys
|
return mappedPerm; // Return null for invalid keys
|
||||||
}).filter(Boolean); // Optionally filter out any null values
|
}).filter(Boolean); // Optionally filter out any null values
|
||||||
|
if (user.id() === props.chat.profile?.id) {
|
||||||
|
perms = [
|
||||||
|
pond.Permission.PERMISSION_READ,
|
||||||
|
pond.Permission.PERMISSION_WRITE
|
||||||
|
]
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// console.error("data.permissions is not an array or does not exist");
|
// console.error("data.permissions is not an array or does not exist");
|
||||||
|
if (user.id() === props.chat.profile?.id) {
|
||||||
|
perms = [
|
||||||
|
pond.Permission.PERMISSION_READ,
|
||||||
|
pond.Permission.PERMISSION_WRITE
|
||||||
|
]
|
||||||
|
} else {
|
||||||
perms = [];
|
perms = [];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return perms
|
return perms
|
||||||
}
|
}
|
||||||
const permissions = generatePermissions()
|
const permissions = generatePermissions()
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ export default function ChatOutput(props: Props) {
|
||||||
<Box ref={containerRef} onScroll={onScroll} style={{
|
<Box ref={containerRef} onScroll={onScroll} style={{
|
||||||
overflowY: "scroll",
|
overflowY: "scroll",
|
||||||
overflowX: "hidden",
|
overflowX: "hidden",
|
||||||
|
height: "100%",
|
||||||
}}>
|
}}>
|
||||||
{props.messages.length < props.totalMessages && (
|
{props.messages.length < props.totalMessages && (
|
||||||
<ListItemButton onClick={seeMore} sx={{ justifyContent: "center"}}>
|
<ListItemButton onClick={seeMore} sx={{ justifyContent: "center"}}>
|
||||||
|
|
|
||||||
111
src/chat/CrispChat.ts
Normal file
111
src/chat/CrispChat.ts
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
import { Crisp } from "crisp-sdk-web";
|
||||||
|
|
||||||
|
const CRISP_HIDDEN_STYLE_ID = "crisp-hide-override";
|
||||||
|
const ANIMATION_DURATION_MS = 300;
|
||||||
|
|
||||||
|
let initialized = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize Crisp and immediately hide the default chat button.
|
||||||
|
* Call this once on app load (e.g., in UserWrapper after user data is ready).
|
||||||
|
*/
|
||||||
|
export function initCrisp(opts: {
|
||||||
|
websiteId: string;
|
||||||
|
email?: string;
|
||||||
|
nickname?: string;
|
||||||
|
phone?: string;
|
||||||
|
tokenId?: string;
|
||||||
|
}) {
|
||||||
|
if (initialized) return;
|
||||||
|
|
||||||
|
Crisp.configure(opts.websiteId);
|
||||||
|
Crisp.session.reset();
|
||||||
|
|
||||||
|
if (opts.email) Crisp.user.setEmail(opts.email);
|
||||||
|
if (opts.nickname) Crisp.user.setNickname(opts.nickname);
|
||||||
|
if (opts.phone) Crisp.user.setPhone(opts.phone);
|
||||||
|
if (opts.tokenId) Crisp.setTokenId(opts.tokenId);
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
|
||||||
|
// Hide the chat button off-screen
|
||||||
|
injectCrispStyles();
|
||||||
|
|
||||||
|
// Auto-hide when the user closes the chat
|
||||||
|
Crisp.chat.onChatClosed(() => {
|
||||||
|
hideCrispChatButton();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject base styles that keep Crisp hidden until we want it.
|
||||||
|
* Uses opacity + visibility so Crisp keeps its default bottom-right positioning.
|
||||||
|
*/
|
||||||
|
function injectCrispStyles() {
|
||||||
|
let style = document.getElementById(CRISP_HIDDEN_STYLE_ID);
|
||||||
|
if (!style) {
|
||||||
|
style = document.createElement("style");
|
||||||
|
style.id = CRISP_HIDDEN_STYLE_ID;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
style.textContent = `
|
||||||
|
#crisp-chatbox {
|
||||||
|
z-index: 99999 !important;
|
||||||
|
transition: opacity ${ANIMATION_DURATION_MS}ms ease-in-out,
|
||||||
|
visibility ${ANIMATION_DURATION_MS}ms ease-in-out !important;
|
||||||
|
opacity: 0 !important;
|
||||||
|
visibility: hidden !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
#crisp-chatbox.crisp-visible {
|
||||||
|
opacity: 1 !important;
|
||||||
|
visibility: visible !important;
|
||||||
|
pointer-events: auto !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the Crisp widget and open the chat window.
|
||||||
|
* Safe to call from any onClick handler.
|
||||||
|
*/
|
||||||
|
export function openCrispChat() {
|
||||||
|
const chatbox = document.getElementById("crisp-chatbox");
|
||||||
|
if (chatbox) {
|
||||||
|
chatbox.classList.add("crisp-visible");
|
||||||
|
setTimeout(() => {
|
||||||
|
Crisp.chat.open();
|
||||||
|
}, ANIMATION_DURATION_MS);
|
||||||
|
} else {
|
||||||
|
Crisp.chat.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the chat window and hide the widget.
|
||||||
|
*/
|
||||||
|
export function closeCrispChat() {
|
||||||
|
Crisp.chat.close();
|
||||||
|
hideCrispChatButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the default Crisp button without opening the chat.
|
||||||
|
*/
|
||||||
|
export function showCrispButton() {
|
||||||
|
const chatbox = document.getElementById("crisp-chatbox");
|
||||||
|
if (chatbox) {
|
||||||
|
chatbox.classList.add("crisp-visible");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide the default Crisp button.
|
||||||
|
*/
|
||||||
|
export function hideCrispChatButton() {
|
||||||
|
const chatbox = document.getElementById("crisp-chatbox");
|
||||||
|
if (chatbox) {
|
||||||
|
chatbox.classList.remove("crisp-visible");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -323,21 +323,21 @@ export default function Devices() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
console.log("has no2: "+hasNo2)
|
// console.log("has no2: "+hasNo2)
|
||||||
}, [hasNo2])
|
// }, [hasNo2])
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
console.log("has co2: "+hasCo2)
|
// console.log("has co2: "+hasCo2)
|
||||||
}, [hasCo2])
|
// }, [hasCo2])
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
console.log("has co: "+hasNo2)
|
// console.log("has co: "+hasNo2)
|
||||||
}, [hasNo2])
|
// }, [hasNo2])
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
console.log("has o2: "+hasO2)
|
// console.log("has o2: "+hasO2)
|
||||||
}, [hasO2])
|
// }, [hasO2])
|
||||||
|
|
||||||
const openProvisionDialog = () => {
|
const openProvisionDialog = () => {
|
||||||
setIsProvisionDialogOpen(true);
|
setIsProvisionDialogOpen(true);
|
||||||
|
|
|
||||||
|
|
@ -223,7 +223,7 @@ export default function TeamPage() {
|
||||||
const isStreamline = IsStreamline()
|
const isStreamline = IsStreamline()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainer spacing={isMobile ? 0 : 2}>
|
<PageContainer spacing={isMobile ? 1 : 2}>
|
||||||
<Box className={classes.container}>
|
<Box className={classes.container}>
|
||||||
<Box className={classes.leftBox}>
|
<Box className={classes.leftBox}>
|
||||||
{title()}
|
{title()}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import MarketWhite from "assets/marketplaceImages/marketplaceIconLight.png";
|
||||||
import MarketBlack from "assets/marketplaceImages/marketplaceIconDark.png";
|
import MarketBlack from "assets/marketplaceImages/marketplaceIconDark.png";
|
||||||
import { ImgIcon } from "common/ImgIcon";
|
import { ImgIcon } from "common/ImgIcon";
|
||||||
import { useThemeType } from "hooks";
|
import { useThemeType } from "hooks";
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
type?: "light" | "dark";
|
type?: "light" | "dark";
|
||||||
|
|
|
||||||
23
src/products/CommonIcons/robotIcon.tsx
Normal file
23
src/products/CommonIcons/robotIcon.tsx
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import RobotWhite from "assets/common/robotIconLight.png";
|
||||||
|
import RobotBlack from "assets/common/robotIconDark.png";
|
||||||
|
import { ImgIcon } from "common/ImgIcon";
|
||||||
|
import { useThemeType } from "hooks";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
type?: "light" | "dark";
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function RobotIcon(props: Props) {
|
||||||
|
const themeType = useThemeType();
|
||||||
|
const { type } = props;
|
||||||
|
|
||||||
|
const src = () => {
|
||||||
|
if (type) {
|
||||||
|
return type === "light" ? RobotWhite : RobotBlack;
|
||||||
|
}
|
||||||
|
|
||||||
|
return themeType === "light" ? RobotBlack : RobotWhite;
|
||||||
|
};
|
||||||
|
|
||||||
|
return <ImgIcon alt="marketplace" src={src()} />;
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
import { useHTTP } from "hooks";
|
import { useHTTP } from "hooks";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { useGlobalState } from "providers";
|
// import { useGlobalState } from "providers";
|
||||||
import { createContext, PropsWithChildren, useContext } from "react";
|
import { createContext, PropsWithChildren, useContext } from "react";
|
||||||
import { pondURL } from "./pond";
|
import { pondURL } from "./pond";
|
||||||
|
|
||||||
|
|
@ -37,7 +37,7 @@ interface Props {}
|
||||||
export default function NoteProvider(props: PropsWithChildren<Props>) {
|
export default function NoteProvider(props: PropsWithChildren<Props>) {
|
||||||
const { children } = props;
|
const { children } = props;
|
||||||
const { get, del, post, put } = useHTTP();
|
const { get, del, post, put } = useHTTP();
|
||||||
const [{as}] = useGlobalState()
|
// const [{as}] = useGlobalState()
|
||||||
|
|
||||||
const addNote = (note: pond.NoteSettings, attachments?: string[]) => {
|
const addNote = (note: pond.NoteSettings, attachments?: string[]) => {
|
||||||
let url = pondURL("/notes" + (attachments ? "?attachments=" + attachments.toString() : ""))
|
let url = pondURL("/notes" + (attachments ? "?attachments=" + attachments.toString() : ""))
|
||||||
|
|
@ -88,9 +88,9 @@ export default function NoteProvider(props: PropsWithChildren<Props>) {
|
||||||
orderBy?: string,
|
orderBy?: string,
|
||||||
search?: string,
|
search?: string,
|
||||||
asRoot?: boolean,
|
asRoot?: boolean,
|
||||||
otherTeam?: string
|
// otherTeam?: string
|
||||||
) => {
|
) => {
|
||||||
const view = otherTeam ? otherTeam : as
|
// const view = otherTeam ? otherTeam : as
|
||||||
let url = pondURL(
|
let url = pondURL(
|
||||||
"/notes" +
|
"/notes" +
|
||||||
"?limit=" +
|
"?limit=" +
|
||||||
|
|
@ -100,9 +100,10 @@ export default function NoteProvider(props: PropsWithChildren<Props>) {
|
||||||
("&order=" + (order ? order : "asc")) +
|
("&order=" + (order ? order : "asc")) +
|
||||||
("&by=" + (orderBy ? orderBy : "key")) +
|
("&by=" + (orderBy ? orderBy : "key")) +
|
||||||
(search ? "&search=" + search : "") +
|
(search ? "&search=" + search : "") +
|
||||||
(asRoot ? "&asRoot=" + asRoot.toString() : "") +
|
(asRoot ? "&asRoot=" + asRoot.toString() : ""),
|
||||||
(view ? "&as=" + view : "")
|
// (view ? "&as=" + "" : "")
|
||||||
)
|
)
|
||||||
|
// console.log(url)
|
||||||
return new Promise<AxiosResponse<pond.ListNotesResponse>>((resolve, reject) => {
|
return new Promise<AxiosResponse<pond.ListNotesResponse>>((resolve, reject) => {
|
||||||
get<pond.ListNotesResponse>(url).then(resp => {
|
get<pond.ListNotesResponse>(url).then(resp => {
|
||||||
resp.data = pond.ListNotesResponse.fromObject(resp.data)
|
resp.data = pond.ListNotesResponse.fromObject(resp.data)
|
||||||
|
|
@ -119,10 +120,10 @@ export default function NoteProvider(props: PropsWithChildren<Props>) {
|
||||||
order?: "asc" | "desc",
|
order?: "asc" | "desc",
|
||||||
orderBy?: string,
|
orderBy?: string,
|
||||||
search?: string,
|
search?: string,
|
||||||
asRoot?: boolean,
|
// asRoot?: boolean,
|
||||||
otherTeam?: string
|
// otherTeam?: string
|
||||||
) => {
|
) => {
|
||||||
const view = otherTeam ? otherTeam : as
|
// const view = otherTeam ? otherTeam : as
|
||||||
let url = pondURL(
|
let url = pondURL(
|
||||||
"/chats" +
|
"/chats" +
|
||||||
"?limit=" +
|
"?limit=" +
|
||||||
|
|
@ -131,10 +132,11 @@ export default function NoteProvider(props: PropsWithChildren<Props>) {
|
||||||
offset +
|
offset +
|
||||||
("&order=" + (order ? order : "asc")) +
|
("&order=" + (order ? order : "asc")) +
|
||||||
("&by=" + (orderBy ? orderBy : "key")) +
|
("&by=" + (orderBy ? orderBy : "key")) +
|
||||||
(search ? "&search=" + search : "") +
|
(search ? "&search=" + search : ""),
|
||||||
(asRoot ? "&asRoot=" + asRoot.toString() : "") +
|
// (asRoot ? "&asRoot=" + asRoot.toString() : ""),
|
||||||
(view ? "&as=" + view : "")
|
// (view ? "&as=" + view : "")
|
||||||
)
|
)
|
||||||
|
// console.log(asRoot)
|
||||||
return new Promise<AxiosResponse<pond.ListChatsResponse>>((resolve, reject) => {
|
return new Promise<AxiosResponse<pond.ListChatsResponse>>((resolve, reject) => {
|
||||||
get<pond.ListChatsResponse>(url).then(resp => {
|
get<pond.ListChatsResponse>(url).then(resp => {
|
||||||
resp.data = pond.ListChatsResponse.fromObject(resp.data)
|
resp.data = pond.ListChatsResponse.fromObject(resp.data)
|
||||||
|
|
|
||||||
|
|
@ -117,9 +117,11 @@ export default function TeamProvider(props: PropsWithChildren<Props>) {
|
||||||
asRoot?: boolean,
|
asRoot?: boolean,
|
||||||
otherTeam?: string,
|
otherTeam?: string,
|
||||||
prefixSearch?: string,
|
prefixSearch?: string,
|
||||||
|
useImitation?: boolean,
|
||||||
) => {
|
) => {
|
||||||
//let asText = team ? "&as=" + team.key() : "";
|
//let asText = team ? "&as=" + team.key() : "";
|
||||||
const view = otherTeam ? otherTeam : (as.length > 0 ? as : undefined)
|
let view = otherTeam ? otherTeam : (as.length > 0 ? as : undefined)
|
||||||
|
if (useImitation === undefined || useImitation === false) view = ""
|
||||||
let url = pondURL(
|
let url = pondURL(
|
||||||
"/teams" +
|
"/teams" +
|
||||||
"?limit=" +
|
"?limit=" +
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue