From 98d87ed8f75b23875031946916ad894d24fe9026 Mon Sep 17 00:00:00 2001 From: Carter Date: Tue, 24 Feb 2026 12:58:35 -0600 Subject: [PATCH 1/7] added column on the left side of the chat drawer for team icons --- src/app/UserWrapper.tsx | 3 -- src/chat/ChatDrawer.tsx | 112 ++++++++++++++++++++++++++-------------- 2 files changed, 73 insertions(+), 42 deletions(-) diff --git a/src/app/UserWrapper.tsx b/src/app/UserWrapper.tsx index bf07306..e69ea85 100644 --- a/src/app/UserWrapper.tsx +++ b/src/app/UserWrapper.tsx @@ -162,10 +162,7 @@ export default function UserWrapper(props: Props) { document.head.appendChild(style); } - console.log(isMobile) - if (isMobile) { - console.log("isMobile") style.textContent = ` #crisp-chatbox [aria-label="Open chat"] { bottom: 6em !important; diff --git a/src/chat/ChatDrawer.tsx b/src/chat/ChatDrawer.tsx index 51f7c2c..1c2c9e9 100644 --- a/src/chat/ChatDrawer.tsx +++ b/src/chat/ChatDrawer.tsx @@ -1,41 +1,39 @@ import { ChevronRight } from "@mui/icons-material"; -import { Box, Drawer, IconButton, Theme, Typography } from "@mui/material"; +import { Avatar, Box, Drawer, IconButton, Theme, Typography } from "@mui/material"; import { makeStyles } from "@mui/styles"; import { useMobile } from "hooks"; import { Team } from "models"; import Chat from "./Chat"; import { pond } from "protobuf-ts/pond"; -const useStyles = makeStyles((theme: Theme) => { - return ({ - chatDrawer: { - display: "flex", - flexDirection: "column", // Arrange children vertically - backgroundColor: theme.palette.background.default, - height: "100%", - maxHeight: "100%", - minHeight: "100%", - minWidth: theme.spacing(54), - maxWidth: theme.spacing(54), - }, - chatContainer: { - flex: 1, - overflow: "hidden", - }, - chatDrawerMobile: { - backgroundColor: theme.palette.background.default, - height: "auto", - width: "100%" - }, - drawerHeader: { - display: "flex", - alignItems: "center", - padding: theme.spacing(1), - ...theme.mixins.toolbar, - justifyContent: "flex-start" - } - }); -}); +const useStyles = makeStyles((theme: Theme) => ({ + chatDrawer: { + display: "flex", + flexDirection: "column", + backgroundColor: theme.palette.background.default, + height: "100%", + maxHeight: "100%", + minHeight: "100%", + minWidth: theme.spacing(54), + maxWidth: theme.spacing(54), + }, + chatContainer: { + flex: 1, + overflow: "hidden", + }, + chatDrawerMobile: { + backgroundColor: theme.palette.background.default, + height: "auto", + width: "100%", + }, + drawerHeader: { + display: "flex", + alignItems: "center", + padding: theme.spacing(1), + ...theme.mixins.toolbar, + justifyContent: "flex-start", + }, +})); interface Props { open: boolean; @@ -48,17 +46,53 @@ export function ChatDrawer(props: Props) { const isMobile = useMobile(); const classes = useStyles() + console.log(team.settings.avatar) + return ( - - - - - + + + {/* Side icon column */} + ({ + backgroundColor: theme.palette.background.paper, + borderRight: `1px solid ${theme.palette.divider}`, + })} + > + {/* Add your icons here */} + + {/* */} + + + + {/* */} - {team.name()} Chat - - + + {/* Main chat area */} + + + + + + {team.name()} Chat + + + + From c33ce3d03a578be1bb16e15101c48f4e92d5e200 Mon Sep 17 00:00:00 2001 From: Carter Date: Wed, 25 Feb 2026 11:05:52 -0600 Subject: [PATCH 2/7] fixed chats not loading --- src/app/HeaderButtons.tsx | 6 +++--- src/chat/Chat.tsx | 1 + src/chat/ChatDrawer.tsx | 7 +------ src/providers/pond/noteAPI.tsx | 26 ++++++++++++++------------ 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/app/HeaderButtons.tsx b/src/app/HeaderButtons.tsx index 18e2f7d..6f8f853 100644 --- a/src/app/HeaderButtons.tsx +++ b/src/app/HeaderButtons.tsx @@ -12,7 +12,7 @@ import { useTeamAPI } from "providers"; import { cloneDeep } from "lodash"; -const useStyles = makeStyles((theme: Theme) => ({ +const useStyles = makeStyles((theme: Theme) => ({ button: { color: getSignatureAccentColour(), width: theme.spacing(6), @@ -70,8 +70,8 @@ export default function HeaderButtons(props: Props) { setHasNewChats(true); return; } - console.log(team.preferences.chatViewedTimestamp) - console.log(team.settings.lastChatTimestamp) + // console.log(team.preferences.chatViewedTimestamp) + // console.log(team.settings.lastChatTimestamp) let viewMoment = moment(team.preferences.chatViewedTimestamp); let chatMoment = moment(team.settings.lastChatTimestamp); if (viewMoment.diff(chatMoment) < 0) { diff --git a/src/chat/Chat.tsx b/src/chat/Chat.tsx index 5b5c8dd..f360ed7 100644 --- a/src/chat/Chat.tsx +++ b/src/chat/Chat.tsx @@ -37,6 +37,7 @@ export default function Chat(props: Props) { const loadChats = () => { setLoading(true) + // console.log("listing chats?") noteAPI.listChats(10, chats.length, "desc", "timestamp", objectKey).then(resp => { setChats(resp.data.chats ? resp.data.chats.reverse().concat(chats) : []) setTotalMessages(resp.data.total) diff --git a/src/chat/ChatDrawer.tsx b/src/chat/ChatDrawer.tsx index 1c2c9e9..534b950 100644 --- a/src/chat/ChatDrawer.tsx +++ b/src/chat/ChatDrawer.tsx @@ -46,7 +46,7 @@ export function ChatDrawer(props: Props) { const isMobile = useMobile(); const classes = useStyles() - console.log(team.settings.avatar) + // console.log(team.settings.avatar) return ( - {/* Add your icons here */} - {/* */} - - {/* */} - {/* Main chat area */} diff --git a/src/providers/pond/noteAPI.tsx b/src/providers/pond/noteAPI.tsx index 259cd61..3cd4f91 100644 --- a/src/providers/pond/noteAPI.tsx +++ b/src/providers/pond/noteAPI.tsx @@ -1,7 +1,7 @@ import { AxiosResponse } from "axios"; import { useHTTP } from "hooks"; import { pond } from "protobuf-ts/pond"; -import { useGlobalState } from "providers"; +// import { useGlobalState } from "providers"; import { createContext, PropsWithChildren, useContext } from "react"; import { pondURL } from "./pond"; @@ -37,7 +37,7 @@ interface Props {} export default function NoteProvider(props: PropsWithChildren) { const { children } = props; const { get, del, post, put } = useHTTP(); - const [{as}] = useGlobalState() + // const [{as}] = useGlobalState() const addNote = (note: pond.NoteSettings, attachments?: string[]) => { let url = pondURL("/notes" + (attachments ? "?attachments=" + attachments.toString() : "")) @@ -88,9 +88,9 @@ export default function NoteProvider(props: PropsWithChildren) { orderBy?: string, search?: string, asRoot?: boolean, - otherTeam?: string + // otherTeam?: string ) => { - const view = otherTeam ? otherTeam : as + // const view = otherTeam ? otherTeam : as let url = pondURL( "/notes" + "?limit=" + @@ -100,9 +100,10 @@ export default function NoteProvider(props: PropsWithChildren) { ("&order=" + (order ? order : "asc")) + ("&by=" + (orderBy ? orderBy : "key")) + (search ? "&search=" + search : "") + - (asRoot ? "&asRoot=" + asRoot.toString() : "") + - (view ? "&as=" + view : "") + (asRoot ? "&asRoot=" + asRoot.toString() : ""), + // (view ? "&as=" + "" : "") ) + // console.log(url) return new Promise>((resolve, reject) => { get(url).then(resp => { resp.data = pond.ListNotesResponse.fromObject(resp.data) @@ -119,10 +120,10 @@ export default function NoteProvider(props: PropsWithChildren) { order?: "asc" | "desc", orderBy?: string, search?: string, - asRoot?: boolean, - otherTeam?: string + // asRoot?: boolean, + // otherTeam?: string ) => { - const view = otherTeam ? otherTeam : as + // const view = otherTeam ? otherTeam : as let url = pondURL( "/chats" + "?limit=" + @@ -131,10 +132,11 @@ export default function NoteProvider(props: PropsWithChildren) { offset + ("&order=" + (order ? order : "asc")) + ("&by=" + (orderBy ? orderBy : "key")) + - (search ? "&search=" + search : "") + - (asRoot ? "&asRoot=" + asRoot.toString() : "") + - (view ? "&as=" + view : "") + (search ? "&search=" + search : ""), + // (asRoot ? "&asRoot=" + asRoot.toString() : ""), + // (view ? "&as=" + view : "") ) + // console.log(asRoot) return new Promise>((resolve, reject) => { get(url).then(resp => { resp.data = pond.ListChatsResponse.fromObject(resp.data) From 5c1434a2e7bef767822e42e6fb97f09183eb7318 Mon Sep 17 00:00:00 2001 From: Carter Date: Wed, 25 Feb 2026 12:01:21 -0600 Subject: [PATCH 3/7] fixed chat drawer mobile formatting --- src/chat/Chat.tsx | 18 ++++++++++-------- src/chat/ChatDrawer.tsx | 4 +++- src/chat/ChatOutput.tsx | 1 + src/pages/Team.tsx | 2 +- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/chat/Chat.tsx b/src/chat/Chat.tsx index f360ed7..fde8a96 100644 --- a/src/chat/Chat.tsx +++ b/src/chat/Chat.tsx @@ -92,14 +92,16 @@ export default function Chat(props: Props) { ) : ( - - - + + + + + diff --git a/src/chat/ChatDrawer.tsx b/src/chat/ChatDrawer.tsx index 534b950..69ba35f 100644 --- a/src/chat/ChatDrawer.tsx +++ b/src/chat/ChatDrawer.tsx @@ -23,8 +23,10 @@ const useStyles = makeStyles((theme: Theme) => ({ }, chatDrawerMobile: { backgroundColor: theme.palette.background.default, - height: "auto", + height: "100vh", width: "100%", + display: "flex", // add this + flexDirection: "column", // add this }, drawerHeader: { display: "flex", diff --git a/src/chat/ChatOutput.tsx b/src/chat/ChatOutput.tsx index a40328e..198690b 100644 --- a/src/chat/ChatOutput.tsx +++ b/src/chat/ChatOutput.tsx @@ -72,6 +72,7 @@ export default function ChatOutput(props: Props) { {props.messages.length < props.totalMessages && ( diff --git a/src/pages/Team.tsx b/src/pages/Team.tsx index 5d2d7ad..1fa32ba 100644 --- a/src/pages/Team.tsx +++ b/src/pages/Team.tsx @@ -223,7 +223,7 @@ export default function TeamPage() { const isStreamline = IsStreamline() return ( - + {title()} From 0ea31c81e4307c26b202e1e2b41a001bbe4c1675 Mon Sep 17 00:00:00 2001 From: Carter Date: Wed, 25 Feb 2026 13:23:24 -0600 Subject: [PATCH 4/7] listing teams in the team chat to select different chats --- src/chat/ChatDrawer.tsx | 47 ++++++++++++++++++++++++++++------ src/providers/pond/teamAPI.tsx | 4 ++- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/chat/ChatDrawer.tsx b/src/chat/ChatDrawer.tsx index 69ba35f..9b02649 100644 --- a/src/chat/ChatDrawer.tsx +++ b/src/chat/ChatDrawer.tsx @@ -5,6 +5,8 @@ import { useMobile } from "hooks"; import { Team } from "models"; import Chat from "./Chat"; import { pond } from "protobuf-ts/pond"; +import { useEffect, useState } from "react"; +import { useTeamAPI } from "providers"; const useStyles = makeStyles((theme: Theme) => ({ chatDrawer: { @@ -25,8 +27,8 @@ const useStyles = makeStyles((theme: Theme) => ({ backgroundColor: theme.palette.background.default, height: "100vh", width: "100%", - display: "flex", // add this - flexDirection: "column", // add this + display: "flex", + flexDirection: "column", }, drawerHeader: { display: "flex", @@ -46,9 +48,17 @@ interface Props { export function ChatDrawer(props: Props) { const { open, onClose, team } = props; const isMobile = useMobile(); - const classes = useStyles() + const classes = useStyles(); + const teamAPI = useTeamAPI(); - // console.log(team.settings.avatar) + const [selectedTeam, setSelectedTeam] = useState(team); + const [teams, setTeams] = useState([]) + + useEffect(() => { + teamAPI.listTeams(10, 0, "desc", "name", undefined, false, undefined).then(resp => { + setTeams(resp.data.teams) + }) + }, [teamAPI]) return ( - + setSelectedTeam(team)} + sx={{ + border: selectedTeam.settings?.key === team.settings.key ? "1px solid white" : "1px solid transparent", + borderRadius: "50%", + }} + > + {teams.map((t, i)=> { + if (t.settings?.key === team.key()) return null; + return ( + setSelectedTeam(Team.create(t))} + sx={{ + border: selectedTeam.key() === t.settings?.key ? "1px solid white" : "1px solid transparent", + borderRadius: "50%", + }} + key={"chat-team-"+i} + > + + + ) + })} {/* Main chat area */} @@ -85,13 +116,13 @@ export function ChatDrawer(props: Props) { - {team.name()} Chat + {selectedTeam.name()} Chat - + - ) + ); } \ No newline at end of file diff --git a/src/providers/pond/teamAPI.tsx b/src/providers/pond/teamAPI.tsx index 9d84091..32f8a4a 100644 --- a/src/providers/pond/teamAPI.tsx +++ b/src/providers/pond/teamAPI.tsx @@ -117,9 +117,11 @@ export default function TeamProvider(props: PropsWithChildren) { asRoot?: boolean, otherTeam?: string, prefixSearch?: string, + useImitation?: boolean, ) => { //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( "/teams" + "?limit=" + From c79c6baa1f8b20f2a06b65d14bb7f8068c91d98e Mon Sep 17 00:00:00 2001 From: Carter Date: Wed, 25 Feb 2026 13:29:38 -0600 Subject: [PATCH 5/7] chat reloads with the selected team's chats --- src/chat/Chat.tsx | 53 +++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/chat/Chat.tsx b/src/chat/Chat.tsx index fde8a96..0bfeea5 100644 --- a/src/chat/Chat.tsx +++ b/src/chat/Chat.tsx @@ -77,35 +77,42 @@ export default function Chat(props: Props) { }; useEffect(() => { - loadChats() - }, []); + setChats([]); + setLoaded(false); + setLoading(false); + setTotalMessages(0); + }, [objectKey]); + + useEffect(() => { + if (chats.length === 0 && !loaded) { + loadChats(); + } + }, [objectKey, chats, loaded]); const loadMore = () => { loadChats(); }; return ( - - { loading && !loaded ? ( - - - - ) : ( - - - + + + {loading && !loaded ? ( + + - - - - - - )} - + ) : ( + + )} + + + + + + ); } From baf59a2b7877e2777065e4ae01a0f0b592138312 Mon Sep 17 00:00:00 2001 From: Carter Date: Wed, 25 Feb 2026 15:14:24 -0600 Subject: [PATCH 6/7] added button to open crisp chat from the chat menu --- src/app/UserWrapper.tsx | 23 ++-- src/assets/common/robotIconDark.png | Bin 0 -> 8672 bytes src/assets/common/robotIconLight.png | Bin 0 -> 3399 bytes src/chat/ChatDrawer.tsx | 15 ++- src/chat/ChatMessage.tsx | 15 ++- src/chat/CrispChat.ts | 111 +++++++++++++++++++ src/pages/Devices.tsx | 24 ++-- src/products/CommonIcons/marketplaceIcon.tsx | 1 - src/products/CommonIcons/robotIcon.tsx | 23 ++++ 9 files changed, 183 insertions(+), 29 deletions(-) create mode 100644 src/assets/common/robotIconDark.png create mode 100644 src/assets/common/robotIconLight.png create mode 100644 src/chat/CrispChat.ts create mode 100644 src/products/CommonIcons/robotIcon.tsx diff --git a/src/app/UserWrapper.tsx b/src/app/UserWrapper.tsx index e69ea85..fac8487 100644 --- a/src/app/UserWrapper.tsx +++ b/src/app/UserWrapper.tsx @@ -14,6 +14,7 @@ import { AppThemeProvider } from 'theme/AppThemeProvider' import HTTPProvider from 'providers/http' import { Crisp } from "crisp-sdk-web"; import { useMobile, useSnackbar } from 'hooks' +import { initCrisp } from '../chat/CrispChat' // import FirmwareLoader from './FirmwareLoader' const reducer = (state: GlobalState, action: GlobalStateAction): GlobalState => { @@ -113,20 +114,14 @@ export default function UserWrapper(props: Props) { }, [setGlobal]) useEffect(() => { - if (!crispInitialized.current && global?.user) { - Crisp.configure(import.meta.env.VITE_CRISP_WEBSITE_ID); - crispInitialized.current = true; - Crisp.session.reset(); - Crisp.user.setEmail(global?.user.settings.email); - // Optional: Set nickname or other info - Crisp.user.setNickname(global?.user.settings.name || global?.user.settings.email); - 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 + if (global?.user) { + initCrisp({ + websiteId: import.meta.env.VITE_CRISP_WEBSITE_ID, + email: global.user.settings.email, + nickname: global.user.settings.name || global.user.settings.email, + phone: global.user.settings.phoneNumber, + tokenId: global.user.id(), + }); } }, [global]); diff --git a/src/assets/common/robotIconDark.png b/src/assets/common/robotIconDark.png new file mode 100644 index 0000000000000000000000000000000000000000..85c8d5149a9a009cea7ea6858a0d3505b07c4ed4 GIT binary patch literal 8672 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 z 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 JzaT6^{}($d@74eS literal 0 HcmV?d00001 diff --git a/src/assets/common/robotIconLight.png b/src/assets/common/robotIconLight.png new file mode 100644 index 0000000000000000000000000000000000000000..724fd18dfd81bf8ea56a17f2f4b5aefaedb7224e GIT binary patch literal 3399 zcmb7GdpK128$XU2W=3%aiHI4MB0aH7v=zsY88L-gr4(TYnTd2IgEN|Ddb*er(M9g5 zpWPo(NwqFX6p}5s$P}quk_a)o{k~@=we26j=h=Ba^PcznUcQ(2yyu+H5%;ysnUpyc z2!dw1u$(+0NSTKJNy@-7@Y~pCa8cUr$z&+C)tbkG0U^kN?EpcA32L(KL@=fWusqoi z6lDTIafcvi5}4xNK+s+b2>|Nl!; ztq_9x*n49MXu@7)ljriK5NptI+7fl+mj3wyO{AFMZv zyd=}iHyMIvuw9%SHXLXl?DROX;GX*G$CB6f!FCf$I(SHb1G&&yH)yjOVp47 z$p5#$iA{eBL(1)whWB&gZU2hbqpP1RUpLZ7>XVRU#u`Ux00~`|4n1`0Xa;h?PUA?r zh7cIbUHOX$0Ff+Q+6_6<-%R8EUL%SF01XBbOPF#eP09gNNzol5Mx%&i|w=pC_$i*C;{eyWRMA

SC=(iS< z+!Tk>?jT!Gu)S$uhQd}Q#Uemb9;@QX@oJW_1Y-n1J5vM5U=MNIJOoQe_%ykUL(?N^ z)h8GP0b>*cJ7$b3&81j|DT0Btos63jru+zIQ_LCdB_?Mfd_12TS++>Q6{#+Gli}T# zE-$?z8R&$iodu)YYY#IY&N`RL;O-mts`oS+3(1@;SQGGS(zw2vJ7^Jwsc`wpK{Z}M zyHt3*WKOHk*3`&zH-v4;C$}VTO)X`&CDuMWwLs5q_Qt^W-Z1;-0Ag~0&2>L(odAt7 z|0P}(Pjga=c&*~&Zr)nqxfOt2vv5?AD{JTI1_m1q(K*cMX&u;@wvgEB4~F9_EEO z^PV(wnpAjUW1NO%LA%HAa|^tJY7TQFow=1`LFK)nm`?C*uV7)zrO+$;g0FKzkD7#D z9Sbh#-EmSUB;P9}DR)PbS4iHb-p16@_0Oz4w63jFwqB>Uq}yt({xwg2>*WjEjB-bc ze@?Vo6Kd@eU)(Zr=WJGe`@sHyJ!iZ^#fMW$e15cYdU(ypK9Jk8kBv<6Y|!!Git3=4 zW!&i8pnG221N*qOu!neo{@mt{gAwl<(`GhE2iiL7>T`LMFA8ru{AZcf`l9~qt>;o1 z=FjR1xbyCoPOYu`*mfh5TveH+v(txCxU0Lenyt3N#(W_9WkJV<9Q`DeyDGHbBnJt# zG0pExFF3Hf@}+7+?Y*|!rsS%=yIx@|O5s7r%6IjoXEw&%*yrMovmf;(=zu-%v&wvA zYMg1VULG9|RmW>t%sn6XR!U&xc0cHdYXk3qT}(eKa4CVaDrTk3cvtQhuBsBh!a}#h zLFU(S#&J^=DJER1d5m~Qs^N8Ba9OJDM!Y0lnpQ%zw+^4d5d?r|4Lm_VQpEulnm+L- zr3P+<*M7#fqMKT~HogO|4XPNO;Y52^(Y1UR(u>7gXc!zSi!eqosqr!8+1m|DNZpDV zut48KAyShW$~N0|OUQT2*}5t_D=pF{^DSrhnGim7C+HO+Hgt(mOm)gHC1gzYUb&jf zpuwMBTsrCp1g+Nbj~U058Ghn{W7d@gy+ys?VZ zBlO-N)NcAS<1cdIt8MME4S?K9F2Y&5k&ny znDLtTXOV2=jERxQqcioSY{sPS)#I-ESI$mez4v*Q?Qq7mBFP;6n!Z>|y@|$~XPylI zZ2cN;}J}eZ!y8U~WCToge{`%#K zUb}2OkrdeLO7th1@9w+2=G@r#3CED`G4 zF3dr&W45PvE`HxQHl&01x+HCXcMcq~s%)O*DW6o;c_0sMet!H6CHoVUfG!)SBm28E z;I=56ZDx`&t(CBMhX^(40)DW-&6_^hjNkQ_&Z-gX8DjZ^jw<)mMNsB z^=|Da5Ag9J1rBqF5#2lew?z@I(jGPI zmoLC32rt7D=k7C;M2f)rsXx^xMl55};J1;s3twd%jL{_Z+`YB@^?}Q%ERfg5d;nH` z8{Xhz+C%DT+PKchd_i`CP0O-DHGOQ)frjO#LIW&cz30&APkpteB?z~b%YC=W2C-1M0#lOH=MlLLy8vQ*#r!$hs?CH|wOl9qjY;l7EB{pZJ) zl%aFX2l5;7<4jB$JbM;A>WR6{=y^1r_B2G+AMu*cH&qw}c2X|(-fA{x$SclD$bevqaR1Y34| zGE-e3pkCoo3cOVBop^^!+pS%&Ouc2u@V$y6cs27F1!)*t( zIarp3nt{+;x~L9jZr8D;6qS3V5KmN^e|dG12;W)5|DFKek@&-7j7;Zz=f$V{R)y(V zIxZ6Bv`Nk-zmmOgTx%Eu6ytlk2p9)ok7FvC$S7T2@9&jO24cWjK>hzI{XTy7%^A$p z5THA3K|UP5zc!7KUOGmx-4hH*c-d~f|c3=AOQnjIj!T0m0+cW)CY(;03dA= h@`Ha%^+CM&z3Sn_{mv@CM&;w#F00o%{l@SU{0~jY02u%P literal 0 HcmV?d00001 diff --git a/src/chat/ChatDrawer.tsx b/src/chat/ChatDrawer.tsx index 9b02649..2ae3081 100644 --- a/src/chat/ChatDrawer.tsx +++ b/src/chat/ChatDrawer.tsx @@ -1,5 +1,5 @@ import { ChevronRight } from "@mui/icons-material"; -import { Avatar, Box, Drawer, IconButton, Theme, Typography } from "@mui/material"; +import { Avatar, Box, Divider, Drawer, IconButton, Theme, Typography } from "@mui/material"; import { makeStyles } from "@mui/styles"; import { useMobile } from "hooks"; import { Team } from "models"; @@ -7,6 +7,8 @@ import Chat from "./Chat"; 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) => ({ chatDrawer: { @@ -60,6 +62,11 @@ export function ChatDrawer(props: Props) { }) }, [teamAPI]) + const openCrisp = () => { + openCrispChat() + onClose() + } + return ( + + + + {teams.map((t, i)=> { if (t.settings?.key === team.key()) return null; return ( diff --git a/src/chat/ChatMessage.tsx b/src/chat/ChatMessage.tsx index ac9600b..50b9b61 100644 --- a/src/chat/ChatMessage.tsx +++ b/src/chat/ChatMessage.tsx @@ -74,9 +74,22 @@ export default function ChatMessage(props: Props) { const mappedPerm = pond.Permission[perm as keyof typeof pond.Permission]; return mappedPerm; // Return null for invalid keys }).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 { // console.error("data.permissions is not an array or does not exist"); - perms = []; + if (user.id() === props.chat.profile?.id) { + perms = [ + pond.Permission.PERMISSION_READ, + pond.Permission.PERMISSION_WRITE + ] + } else { + perms = []; + } } return perms } diff --git a/src/chat/CrispChat.ts b/src/chat/CrispChat.ts new file mode 100644 index 0000000..a0220fb --- /dev/null +++ b/src/chat/CrispChat.ts @@ -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"); + } +} \ No newline at end of file diff --git a/src/pages/Devices.tsx b/src/pages/Devices.tsx index 0e030c1..80a3f0d 100644 --- a/src/pages/Devices.tsx +++ b/src/pages/Devices.tsx @@ -323,21 +323,21 @@ export default function Devices() { return false } - useEffect(() => { - console.log("has no2: "+hasNo2) - }, [hasNo2]) + // useEffect(() => { + // console.log("has no2: "+hasNo2) + // }, [hasNo2]) - useEffect(() => { - console.log("has co2: "+hasCo2) - }, [hasCo2]) + // useEffect(() => { + // console.log("has co2: "+hasCo2) + // }, [hasCo2]) - useEffect(() => { - console.log("has co: "+hasNo2) - }, [hasNo2]) + // useEffect(() => { + // console.log("has co: "+hasNo2) + // }, [hasNo2]) - useEffect(() => { - console.log("has o2: "+hasO2) - }, [hasO2]) + // useEffect(() => { + // console.log("has o2: "+hasO2) + // }, [hasO2]) const openProvisionDialog = () => { setIsProvisionDialogOpen(true); diff --git a/src/products/CommonIcons/marketplaceIcon.tsx b/src/products/CommonIcons/marketplaceIcon.tsx index 20933b9..ca2f35b 100644 --- a/src/products/CommonIcons/marketplaceIcon.tsx +++ b/src/products/CommonIcons/marketplaceIcon.tsx @@ -2,7 +2,6 @@ import MarketWhite from "assets/marketplaceImages/marketplaceIconLight.png"; import MarketBlack from "assets/marketplaceImages/marketplaceIconDark.png"; import { ImgIcon } from "common/ImgIcon"; import { useThemeType } from "hooks"; -import React from "react"; interface Props { type?: "light" | "dark"; diff --git a/src/products/CommonIcons/robotIcon.tsx b/src/products/CommonIcons/robotIcon.tsx new file mode 100644 index 0000000..8c86754 --- /dev/null +++ b/src/products/CommonIcons/robotIcon.tsx @@ -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 ; +} From 9ab1d530e7eb831b61900be6eb7c35e7307bc156 Mon Sep 17 00:00:00 2001 From: Carter Date: Wed, 25 Feb 2026 15:19:58 -0600 Subject: [PATCH 7/7] added tooltips for the icons in the chat menu --- src/chat/ChatDrawer.tsx | 55 ++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/src/chat/ChatDrawer.tsx b/src/chat/ChatDrawer.tsx index 2ae3081..ecf83b7 100644 --- a/src/chat/ChatDrawer.tsx +++ b/src/chat/ChatDrawer.tsx @@ -1,5 +1,5 @@ import { ChevronRight } from "@mui/icons-material"; -import { Avatar, Box, Divider, 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 { useMobile } from "hooks"; import { Team } from "models"; @@ -91,34 +91,39 @@ export function ChatDrawer(props: Props) { borderRight: `1px solid ${theme.palette.divider}`, })} > - setSelectedTeam(team)} - sx={{ - border: selectedTeam.settings?.key === team.settings.key ? "1px solid white" : "1px solid transparent", - borderRadius: "50%", - }} - > - - - - - + + setSelectedTeam(team)} + sx={{ + border: selectedTeam.settings?.key === team.settings.key ? "1px solid white" : "1px solid transparent", + borderRadius: "50%", + }} + > + + + + + + + + {teams.map((t, i)=> { if (t.settings?.key === team.key()) return null; return ( - setSelectedTeam(Team.create(t))} - sx={{ - border: selectedTeam.key() === t.settings?.key ? "1px solid white" : "1px solid transparent", - borderRadius: "50%", - }} - key={"chat-team-"+i} - > - - + + setSelectedTeam(Team.create(t))} + sx={{ + border: selectedTeam.key() === t.settings?.key ? "1px solid white" : "1px solid transparent", + borderRadius: "50%", + }} + > + + + ) })}