adding a bunch of linting and starting project over with nothing

This commit is contained in:
talksik
2022-05-12 17:01:27 -05:00
parent f7646c4350
commit 3b1df3173c
34 changed files with 31766 additions and 1058 deletions
+30667
View File
File diff suppressed because it is too large Load Diff
+13 -11
View File
@@ -1,17 +1,19 @@
{ {
"env": { "env": {
"browser": true, "browser": true,
"es6": true, "es2021": true,
"node": true "node": true
}, },
"extends": [ "extends": ["plugin:react/recommended", "airbnb", "airbnb/hooks", "airbnb-typescript"],
"eslint:recommended", "parser": "@typescript-eslint/parser",
"plugin:@typescript-eslint/eslint-recommended", "parserOptions": {
"plugin:@typescript-eslint/recommended", "project": "./tsconfig.json"
"plugin:import/recommended", },
"plugin:import/electron", "plugins": ["react", "@typescript-eslint"],
"plugin:import/typescript", "rules": {
"plugin:reac/recommended" "no-shadow": "off",
], "@typescript-eslint/no-shadow": ["error"],
"parser": "@typescript-eslint/parser" "no-unused-vars": "warn",
"@typescript-eslint/no-unused-vars": "warn"
}
} }
+9 -4
View File
@@ -74,14 +74,19 @@
"@electron-forge/plugin-webpack": "6.0.0-beta.63", "@electron-forge/plugin-webpack": "6.0.0-beta.63",
"@types/react": "^17.0.40", "@types/react": "^17.0.40",
"@types/react-dom": "^17.0.13", "@types/react-dom": "^17.0.13",
"@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/eslint-plugin": "^5.13.0",
"@typescript-eslint/parser": "^5.0.0", "@typescript-eslint/parser": "^5.0.0",
"@vercel/webpack-asset-relocator-loader": "1.7.0", "@vercel/webpack-asset-relocator-loader": "1.7.0",
"autoprefixer": "^10.4.4", "autoprefixer": "^10.4.4",
"css-loader": "^6.0.0", "css-loader": "^6.0.0",
"electron": "17.1.2", "electron": "17.1.2",
"eslint": "^8.0.1", "eslint": "^8.15.0",
"eslint-plugin-import": "^2.25.0", "eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^17.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-react": "^7.29.4",
"eslint-plugin-react-hooks": "^4.5.0",
"fork-ts-checker-webpack-plugin": "^6.0.1", "fork-ts-checker-webpack-plugin": "^6.0.1",
"mini-css-extract-plugin": "^2.6.0", "mini-css-extract-plugin": "^2.6.0",
"node-loader": "^2.0.0", "node-loader": "^2.0.0",
@@ -98,8 +103,8 @@
}, },
"dependencies": { "dependencies": {
"@getstation/electron-google-oauth2": "^2.1.0", "@getstation/electron-google-oauth2": "^2.1.0",
"@nirvana/core": "*",
"@nirvana/components": "*", "@nirvana/components": "*",
"@nirvana/core": "*",
"antd": "^4.20.2", "antd": "^4.20.2",
"axios": "^0.26.1", "axios": "^0.26.1",
"electron-squirrel-startup": "^1.0.0", "electron-squirrel-startup": "^1.0.0",
-12
View File
@@ -1,12 +0,0 @@
import "./styles/index.css";
import * as React from "react";
import * as ReactDOM from "react-dom";
import NirvanaApp from "./pages/nirvanaApp";
function render() {
ReactDOM.render(<NirvanaApp />, document.getElementById("root"));
}
render();
+10 -11
View File
@@ -1,23 +1,24 @@
// NOTE: DO NOT ADD ANY ELECTRON RELATED TYPESCRIPT HERE...KEEP IT ONLY TYPESCRIPT OTHERWISE // NOTE: DO NOT ADD ANY ELECTRON RELATED TYPESCRIPT HERE...KEEP IT ONLY TYPESCRIPT OTHERWISE
// THE RENDERER WONT BE ABLE TO ACCESS THIS AS IT WILL THINK ITS PART OF MAIN PROCESS SINCE RENDERER CAN'T ACCESS NODE STUFF // THE RENDERER WONT BE ABLE TO ACCESS THIS AS IT WILL THINK ITS PART
// OF MAIN PROCESS SINCE RENDERER CAN'T ACCESS NODE STUFF
// SINCE IT's NOT A NODE PROCESS // SINCE IT's NOT A NODE PROCESS
enum Channels { export enum Channels {
ACTIVATE_LOG_IN = "ACTIVATE_LOG_IN", ACTIVATE_LOG_IN = 'ACTIVATE_LOG_IN',
GOOGLE_AUTH_TOKENS = "GOOGLE_AUTH_TOKENS", GOOGLE_AUTH_TOKENS = 'GOOGLE_AUTH_TOKENS',
RESIZE_WINDOW = "RESIZE_WINDOW", RESIZE_WINDOW = 'RESIZE_WINDOW',
ON_WINDOW_BLUR = "ON_WINDOW_BLUR", ON_WINDOW_BLUR = 'ON_WINDOW_BLUR',
} }
export enum STORE_ITEMS { export enum StoreItems {
AUTH_SESSION_JWT = "AUTH_SESSION_JWT", AUTH_SESSION_JWT = 'AUTH_SESSION_JWT',
} }
export type Dimensions = { height: number; width: number }; export type Dimensions = { height: number; width: number };
export interface DimensionChangeRequest { export interface DimensionChangeRequest {
setAlwaysOnTop: boolean; setAlwaysOnTop: boolean;
setPosition?: "topRight" | "center"; setPosition?: 'topRight' | 'center';
dimensions: Dimensions; dimensions: Dimensions;
addDimensions: boolean; addDimensions: boolean;
} }
@@ -28,5 +29,3 @@ export const OVERLAY_ONLY_INITIAL_PRESET: Dimensions = {
height: 50, height: 50,
width: 325, width: 325,
}; };
export default Channels;
+2 -2
View File
@@ -1,5 +1,5 @@
import { Dimensions, DimensionChangeRequest } from "./constants"; /* eslint-disable no-unused-vars */
import { electronAPI } from "./preload"; import { DimensionChangeRequest, STORE_ITEMS, Channels } from './constants';
export {}; export {};
declare global { declare global {
@@ -1,20 +0,0 @@
import Channels, { STORE_ITEMS } from "./constants";
import ElectronGoogleOAuth2 from "@getstation/electron-google-oauth2";
import { browserWindow } from "../index";
import { ipcMain } from "electron";
import store from "./store";
const myApiOauth = new ElectronGoogleOAuth2(
"423533244953-banligobgbof8hg89i6cr1l7u0p7c2pk.apps.googleusercontent.com",
"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",
[""],
{ successRedirectURL: "http://localhost:3000/auth/success" }
);
// FRESH GOOGLE LOGIN...either no json web tokens or trying to sign in with another account.
export async function handleGoogleLogin() {
const tokens = await myApiOauth.openAuthWindowAndGetTokens();
browserWindow.webContents.send(Channels.GOOGLE_AUTH_TOKENS, tokens);
}
+9 -10
View File
@@ -1,7 +1,6 @@
import Channels, { Dimensions } from "./constants"; // eslint-disable-next-line import/no-extraneous-dependencies
import { contextBridge, ipcRenderer } from "electron"; import { contextBridge, ipcRenderer } from 'electron';
import { Channels, Dimensions, StoreItems } from './constants';
import { STORE_ITEMS } from "./constants";
const electronAPI = { const electronAPI = {
auth: { auth: {
@@ -10,11 +9,11 @@ const electronAPI = {
}, },
}, },
store: { store: {
get(val: STORE_ITEMS) { get(val: StoreItems) {
return ipcRenderer.invoke("electron-store-get", val); return ipcRenderer.invoke('electron-store-get', val);
}, },
set(property: STORE_ITEMS, val: any) { set(property: StoreItems, val: any) {
ipcRenderer.send("electron-store-set", property, val); ipcRenderer.send('electron-store-set', property, val);
}, },
// Other method you want to add like has(), reset(), etc. // Other method you want to add like has(), reset(), etc.
}, },
@@ -26,7 +25,7 @@ const electronAPI = {
}, },
on(channel: Channels, func: any) { on(channel: Channels, func: any) {
const validChannels = ["ipc-example"]; // const validChannels = ['ipc-example'];
// if (validChannels.includes(channel)) { // if (validChannels.includes(channel)) {
// // Deliberately strip event as it includes `sender` // // Deliberately strip event as it includes `sender`
// ipcRenderer.on(channel, (event, ...args) => func(...args)); // ipcRenderer.on(channel, (event, ...args) => func(...args));
@@ -45,6 +44,6 @@ const electronAPI = {
}, },
}; };
contextBridge.exposeInMainWorld("electronAPI", electronAPI); contextBridge.exposeInMainWorld('electronAPI', electronAPI);
export default electronAPI; export default electronAPI;
+11
View File
@@ -0,0 +1,11 @@
/* eslint-disable react/jsx-filename-extension */
import './styles/index.css';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
function render() {
ReactDOM.render(<div>this is the electron app</div>, document.getElementById('root'));
}
render();
+44 -43
View File
@@ -1,19 +1,12 @@
import { /* eslint-disable import/no-extraneous-dependencies */
BrowserWindow, // eslint-disable-next-line object-curly-newline
Display, import { BrowserWindow, Display, app, ipcMain, screen } from 'electron';
Menu,
app,
dialog,
globalShortcut,
ipcMain,
screen,
} from "electron";
import Channels, { DEFAULT_APP_PRESET } from "./electron/constants";
import { DimensionChangeRequest } from "./electron/constants"; import path from 'path';
import { handleGoogleLogin } from "./electron/handleLogin"; import ElectronGoogleOAuth2 from '@getstation/electron-google-oauth2';
import path from "path"; import { Channels, DEFAULT_APP_PRESET, DimensionChangeRequest } from './electron/constants';
import store from "./electron/store";
import store from './electron/store';
// This allows TypeScript to pick up the magic constant that's auto-generated by Forge's Webpack // This allows TypeScript to pick up the magic constant that's auto-generated by Forge's Webpack
// plugin that tells the Electron app where to look for the Webpack-bundled app code (depending on // plugin that tells the Electron app where to look for the Webpack-bundled app code (depending on
@@ -22,14 +15,29 @@ declare const MAIN_WINDOW_WEBPACK_ENTRY: string;
declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: string; declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: string;
// Handle creating/removing shortcuts on Windows when installing/uninstalling. // Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require("electron-squirrel-startup")) { // eslint-disable-next-line global-require
if (require('electron-squirrel-startup')) {
// eslint-disable-line global-require // eslint-disable-line global-require
app.quit(); app.quit();
} }
// Keep a global reference of the window object, if you don't, the window will // Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected. // be closed automatically when the JavaScript object is garbage collected.
export let browserWindow: BrowserWindow; let browserWindow: BrowserWindow;
const myApiOauth = new ElectronGoogleOAuth2(
'423533244953-banligobgbof8hg89i6cr1l7u0p7c2pk.apps.googleusercontent.com',
'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',
[''],
{ successRedirectURL: 'http://localhost:3000/auth/success' },
);
// FRESH GOOGLE LOGIN...either no json web tokens or trying to sign in with another account.
export default async function handleGoogleLogin() {
const tokens = await myApiOauth.openAuthWindowAndGetTokens();
browserWindow.webContents.send(Channels.GOOGLE_AUTH_TOKENS, tokens);
}
let display: Display; let display: Display;
@@ -41,7 +49,7 @@ const createWindow = (): void => {
preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY, preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
sandbox: true, sandbox: true,
}, },
icon: "./assets/1024x1024.icns", icon: './assets/1024x1024.icns',
// transparent: true, // transparent: true,
@@ -60,7 +68,7 @@ const createWindow = (): void => {
browserWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY); browserWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);
// Open the DevTools. // Open the DevTools.
browserWindow.webContents.openDevTools({ mode: "detach" }); browserWindow.webContents.openDevTools({ mode: 'detach' });
display = screen.getPrimaryDisplay(); display = screen.getPrimaryDisplay();
}; };
@@ -74,15 +82,15 @@ app
.then(() => { .then(() => {
// activate login // activate login
ipcMain.on(Channels.ACTIVATE_LOG_IN, async (event, arg) => { ipcMain.on(Channels.ACTIVATE_LOG_IN, async (event, arg) => {
console.log("initiating log in"); console.log('initiating log in');
await handleGoogleLogin(); await handleGoogleLogin();
}); });
// access storage/cookies // access storage/cookies
ipcMain.on("electron-store-set", async (event, key, val) => { ipcMain.on('electron-store-set', async (event, key, val) => {
store.set(key, val); store.set(key, val);
}); });
ipcMain.handle("electron-store-get", async (event, val) => { ipcMain.handle('electron-store-get', async (event, val) => {
const result = await store.get(val); const result = await store.get(val);
return result; return result;
}); });
@@ -90,7 +98,7 @@ app
// dynamically changing the window bounds // dynamically changing the window bounds
ipcMain.on(Channels.RESIZE_WINDOW, (event, req: DimensionChangeRequest) => { ipcMain.on(Channels.RESIZE_WINDOW, (event, req: DimensionChangeRequest) => {
if (req.setAlwaysOnTop) { if (req.setAlwaysOnTop) {
browserWindow.setAlwaysOnTop(true, "floating"); browserWindow.setAlwaysOnTop(true, 'floating');
} else { } else {
browserWindow.setAlwaysOnTop(false); browserWindow.setAlwaysOnTop(false);
} }
@@ -100,26 +108,19 @@ app
browserWindow.setSize( browserWindow.setSize(
currentDimensions[0] + req.dimensions.width, currentDimensions[0] + req.dimensions.width,
currentDimensions[1] + req.dimensions.height, currentDimensions[1] + req.dimensions.height,
false false,
); );
} else { } else {
browserWindow.setSize( browserWindow.setSize(req.dimensions.width, req.dimensions.height, false);
req.dimensions.width,
req.dimensions.height,
false
);
} }
if (req.setPosition) { if (req.setPosition) {
if (req.setPosition === "center") { if (req.setPosition === 'center') {
browserWindow.center(); browserWindow.center();
} }
if (req.setPosition === "topRight") { if (req.setPosition === 'topRight') {
browserWindow.setPosition( browserWindow.setPosition(display.bounds.width - req.dimensions.width, 0);
display.bounds.width - req.dimensions.width,
0
);
} }
} }
}); });
@@ -130,7 +131,7 @@ app
// }); // });
// on blur, show overlay, and tell app to trigger overlay mode // on blur, show overlay, and tell app to trigger overlay mode
browserWindow.on("blur", () => { browserWindow.on('blur', () => {
browserWindow.webContents.send(Channels.ON_WINDOW_BLUR); browserWindow.webContents.send(Channels.ON_WINDOW_BLUR);
}); });
}); });
@@ -138,13 +139,13 @@ app
// Quit when all windows are closed, except on macOS. There, it's common // Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits // for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q. // explicitly with Cmd + Q.
app.on("window-all-closed", () => { app.on('window-all-closed', () => {
if (process.platform !== "darwin") { if (process.platform !== 'darwin') {
app.quit(); app.quit();
} }
}); });
app.on("activate", () => { app.on('activate', () => {
// On OS X it's common to re-create a window in the app when the // On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open. // dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) { if (BrowserWindow.getAllWindows().length === 0) {
@@ -158,17 +159,17 @@ app.on("activate", () => {
// open deep links from nirvana web app // open deep links from nirvana web app
if (process.defaultApp) { if (process.defaultApp) {
if (process.argv.length >= 2) { if (process.argv.length >= 2) {
app.setAsDefaultProtocolClient("nirvana-desktop", process.execPath, [ app.setAsDefaultProtocolClient('nirvana-desktop', process.execPath, [
path.resolve(process.argv[1]), path.resolve(process.argv[1]),
]); ]);
} }
} else { } else {
app.setAsDefaultProtocolClient("nirvana-desktop"); app.setAsDefaultProtocolClient('nirvana-desktop');
} }
// Handle the protocol. In this case, we choose to show an Error Box. // Handle the protocol. In this case, we choose to show an Error Box.
app.on("open-url", (event, url) => { app.on('open-url', (event, url) => {
console.log("welcome back, you arrived from: ", url); console.log('welcome back, you arrived from: ', url);
browserWindow.focus(); browserWindow.focus();
}); });
+2 -4
View File
@@ -28,8 +28,6 @@
// import './index.css'; // import './index.css';
import "./app"; import './electronApp';
console.log( console.log('👋 This message is being logged by "renderer.js", included via webpack');
'👋 This message is being logged by "renderer.js", included via webpack'
);
+10 -9
View File
@@ -1,19 +1,20 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true, "allowJs": true,
"module": "commonjs",
"skipLibCheck": true, "skipLibCheck": true,
"esModuleInterop": true, "esModuleInterop": true,
"noImplicitAny": false, "allowSyntheticDefaultImports": true,
"sourceMap": true, "strict": true,
"baseUrl": ".", "forceConsistentCasingInFileNames": true,
"outDir": "dist", "noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node", "moduleResolution": "node",
"resolveJsonModule": true, "resolveJsonModule": true,
"paths": { "isolatedModules": true,
"*": ["node_modules/*"] "noEmit": true,
},
"jsx": "react-jsx" "jsx": "react-jsx"
}, },
"include": ["src/**/*"] "include": ["src/"]
} }
@@ -1,12 +1,12 @@
import { useAuthCheck, useServerCheck } from "../../controller/index"; import { useAuthCheck, useServerCheck } from '../../../src/controller/index';
import { $jwtToken } from "../../controller/recoil"; import { $jwtToken } from '../../../src/controller/recoil';
import Login from "../../pages/Login"; import Login from '../../Login';
import NirvanaApi from "../../controller/nirvanaApi"; import NirvanaApi from '../../../src/controller/nirvanaApi';
import { STORE_ITEMS } from "../../electron/constants"; import { STORE_ITEMS } from '../../../src/electron/constants';
import SkeletonLoader from "../loading/skeleton"; import SkeletonLoader from '../loading/skeleton';
import { useEffect } from "react"; import { useEffect } from 'react';
import { useRecoilState } from "recoil"; import { useRecoilState } from 'recoil';
export default function ProtectedRoute({ export default function ProtectedRoute({
children, children,
@@ -47,7 +47,7 @@ export default function ProtectedRoute({
// }, []); // }, []);
useEffect(() => { useEffect(() => {
console.log("change in jwt token", jwtToken); console.log('change in jwt token', jwtToken);
if (jwtToken) { if (jwtToken) {
window.electronAPI.store.set(STORE_ITEMS.AUTH_SESSION_JWT, jwtToken); window.electronAPI.store.set(STORE_ITEMS.AUTH_SESSION_JWT, jwtToken);
@@ -64,7 +64,7 @@ export default function ProtectedRoute({
// first time loading // first time loading
if (serverLoading) if (serverLoading)
return ( return (
<span className="text-md text-gray-400 flex items-center justify-center flex-1 text-center p-5 h-screen"> <span className='text-md text-gray-400 flex items-center justify-center flex-1 text-center p-5 h-screen'>
Sorry...this is our bad. Our servers are loading. We are trying our best Sorry...this is our bad. Our servers are loading. We are trying our best
to back up and running! :) <br /> Please contact me for urgent concerns: to back up and running! :) <br /> Please contact me for urgent concerns:
arjunpatel@berkeley.edu arjunpatel@berkeley.edu
@@ -73,7 +73,7 @@ export default function ProtectedRoute({
if (isLoading) { if (isLoading) {
return ( return (
<div className="container h-screen w-screen flex flex-col justify-center mx-10"> <div className='container h-screen w-screen flex flex-col justify-center mx-10'>
<SkeletonLoader /> <SkeletonLoader />
</div> </div>
); );
@@ -1,4 +1,4 @@
import { FiActivity, FiSun } from "react-icons/fi"; import { FiActivity, FiSun } from 'react-icons/fi';
import { import {
RtcAnswerRequest, RtcAnswerRequest,
RtcCallRequest, RtcCallRequest,
@@ -6,21 +6,21 @@ import {
RtcReceiveAnswerResponse, RtcReceiveAnswerResponse,
ServerResponseChannels, ServerResponseChannels,
SomeoneUntunedFromLineResponse, SomeoneUntunedFromLineResponse,
} from "@nirvana/core/sockets/channels"; } from '@nirvana/core/sockets/channels';
import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { $selectedLineId } from "../../../controller/recoil"; import { $selectedLineId } from '../../../controller/recoil';
import { Avatar } from "antd"; import { Avatar } from 'antd';
import LineIcon from "../lineIcon"; import LineIcon from '../lineIcon';
import { LineMemberState } from "@nirvana/core/models/line.model"; import { LineMemberState } from '@nirvana/core/models/line.model';
import MasterLineData from "@nirvana/core/models/masterLineData.model"; import MasterLineData from '@nirvana/core/models/masterLineData.model';
import Peer from "simple-peer"; import Peer from 'simple-peer';
import { ServerRequestChannels } from "../../../../../core/sockets/channels"; import { ServerRequestChannels } from '@nirvana/core/sockets/channels';
import moment from "moment"; import moment from 'moment';
import toast from "react-hot-toast"; import toast from 'react-hot-toast';
import { useGetUserDetails } from "../../../controller/index"; import { useGetUserDetails } from '../../../controller/index';
import { useLineDataProvider } from "../../../controller/lineDataProvider"; import { useLineDataProvider } from '../../../controller/lineDataProvider';
import { useRecoilState } from "recoil"; import { useRecoilState } from 'recoil';
// todo: send a much more comprehensive master line object? or just add properties to the // todo: send a much more comprehensive master line object? or just add properties to the
// masterLineData object so that we don't have different models to maintain between client and server // masterLineData object so that we don't have different models to maintain between client and server
@@ -36,9 +36,9 @@ export default function LineRow({
const { data: userData } = useGetUserDetails(); const { data: userData } = useGetUserDetails();
useEffect(() => { useEffect(() => {
console.warn("mounting linerow"); console.warn('mounting linerow');
return () => console.warn("UNMOUNTING line row"); return () => console.warn('UNMOUNTING line row');
}, []); }, []);
// take the source of truth list of memeberIds tuned in, and see if I'm in it // take the source of truth list of memeberIds tuned in, and see if I'm in it
@@ -54,19 +54,19 @@ export default function LineRow({
const renderActivityIcon = useMemo(() => { const renderActivityIcon = useMemo(() => {
// if there is someone or me broadcasting here // if there is someone or me broadcasting here
if (masterLineData.currentBroadcastersUserIds?.length > 0) if (masterLineData.currentBroadcastersUserIds?.length > 0)
return <FiSun className="text-teal-500 animate-pulse" />; return <FiSun className='text-teal-500 animate-pulse' />;
if (isUserTunedIn) if (isUserTunedIn)
return <FiActivity className="text-black animate-pulse" />; return <FiActivity className='text-black animate-pulse' />;
// if there is new activity blocks for me // if there is new activity blocks for me
if (masterLineData.currentUserMember.lastVisitDate) if (masterLineData.currentUserMember.lastVisitDate)
return ( return (
<span className="h-2 w-2 rounded-full bg-slate-800 animate-pulse"></span> <span className='h-2 w-2 rounded-full bg-slate-800 animate-pulse'></span>
); );
return ( return (
<span className="h-2 w-2 rounded-full bg-white animate-pulse"></span> <span className='h-2 w-2 rounded-full bg-white animate-pulse'></span>
); );
}, [masterLineData, isUserTunedIn]); }, [masterLineData, isUserTunedIn]);
@@ -77,22 +77,22 @@ export default function LineRow({
<Avatar.Group <Avatar.Group
key={`lineRowRightActivityGroup-${masterLineData.lineDetails._id.toString()}`} key={`lineRowRightActivityGroup-${masterLineData.lineDetails._id.toString()}`}
maxCount={2} maxCount={2}
maxPopoverTrigger="click" maxPopoverTrigger='click'
size="small" size='small'
maxStyle={{ maxStyle={{
color: "#f56a00", color: '#f56a00',
backgroundColor: "#fde3cf", backgroundColor: '#fde3cf',
cursor: "pointer", cursor: 'pointer',
borderRadius: "0", borderRadius: '0',
}} }}
className="shadow-lg" className='shadow-lg'
> >
{masterLineData.otherUserObjects?.map((otherUser, index) => ( {masterLineData.otherUserObjects?.map((otherUser, index) => (
<Avatar <Avatar
key={`lineListActivitySection-${otherUser._id.toString()}-${index}`} key={`lineListActivitySection-${otherUser._id.toString()}-${index}`}
src={otherUser.picture ?? ""} src={otherUser.picture ?? ''}
shape="square" shape='square'
size={"small"} size={'small'}
/> />
))} ))}
</Avatar.Group> </Avatar.Group>
@@ -137,11 +137,11 @@ export default function LineRow({
className={`flex flex-row items-center justify-start gap-2 p-2 px-4 h-14 hover:bg-gray-200 cursor-pointer transition-all className={`flex flex-row items-center justify-start gap-2 p-2 px-4 h-14 hover:bg-gray-200 cursor-pointer transition-all
last:border-b-0 border-b border-b-gray-200 relative z-50 rounded ${ last:border-b-0 border-b border-b-gray-200 relative z-50 rounded ${
selectedLineId === masterLineData.lineDetails._id.toString() && selectedLineId === masterLineData.lineDetails._id.toString() &&
"bg-gray-200 scale-110 shadow-2xl translate-x-3" 'bg-gray-200 scale-110 shadow-2xl translate-x-3'
}`} }`}
> >
{/* status dot */} {/* status dot */}
<div className="flex-shrink-0 h-4 w-4">{renderActivityIcon}</div> <div className='flex-shrink-0 h-4 w-4'>{renderActivityIcon}</div>
{profilePictures && ( {profilePictures && (
<LineIcon grayscale={!isUserTunedIn} sourceImages={profilePictures} /> <LineIcon grayscale={!isUserTunedIn} sourceImages={profilePictures} />
@@ -150,15 +150,15 @@ export default function LineRow({
<h2 <h2
className={`text-inherit text-md max-w-[220px] truncate text-slate-800 ${ className={`text-inherit text-md max-w-[220px] truncate text-slate-800 ${
masterLineData.currentUserMember.lastVisitDate masterLineData.currentUserMember.lastVisitDate
? "font-semibold" ? 'font-semibold'
: "" : ''
}`} }`}
> >
{masterLineData.lineDetails.name || {masterLineData.lineDetails.name ||
masterLineData.otherUserObjects[0].givenName} masterLineData.otherUserObjects[0].givenName}
</h2> </h2>
<div className="ml-auto flex-shrink-0">{renderRightActivity}</div> <div className='ml-auto flex-shrink-0'>{renderRightActivity}</div>
</div> </div>
{/* mounts and unmounts based on if in the room or now */} {/* mounts and unmounts based on if in the room or now */}
@@ -249,7 +249,7 @@ function StreamRoom({
localPeerConnections[otherTunedInUserId] = localPeerInitiator; localPeerConnections[otherTunedInUserId] = localPeerInitiator;
// notify each one with specific signal // notify each one with specific signal
localPeerInitiator.on("signal", (signal) => { localPeerInitiator.on('signal', (signal) => {
$ws.emit( $ws.emit(
ServerRequestChannels.RTC_CALL_REQUEST, ServerRequestChannels.RTC_CALL_REQUEST,
new RtcCallRequest(lineId, otherTunedInUserId, signal) new RtcCallRequest(lineId, otherTunedInUserId, signal)
@@ -266,7 +266,7 @@ function StreamRoom({
// create a local peer connection for this new user // create a local peer connection for this new user
console.log( console.log(
"ooo newbie joined room, I guess I will accept it and send him my signal" 'ooo newbie joined room, I guess I will accept it and send him my signal'
); );
console.log(res); console.log(res);
@@ -276,9 +276,9 @@ function StreamRoom({
stream: userStream, // add in my own stream that I got before stream: userStream, // add in my own stream that I got before
}); });
peerForMeAndNewbie.on("signal", (signal) => { peerForMeAndNewbie.on('signal', (signal) => {
console.log( console.log(
"as the answerer, I am going to send back my signal so that the newbie can update his local peer for me" 'as the answerer, I am going to send back my signal so that the newbie can update his local peer for me'
); );
$ws.emit( $ws.emit(
ServerRequestChannels.RTC_ANSWER_REQUEST, ServerRequestChannels.RTC_ANSWER_REQUEST,
@@ -315,7 +315,7 @@ function StreamRoom({
const newUserPeerMap = { ...previousUserPeersMap }; const newUserPeerMap = { ...previousUserPeersMap };
console.log( console.log(
"here is the current peers map", 'here is the current peers map',
previousUserPeersMap previousUserPeersMap
); );
@@ -325,7 +325,7 @@ function StreamRoom({
peerForAnswerer.signal(res.simplePeerSignal); peerForAnswerer.signal(res.simplePeerSignal);
} else { } else {
console.error( console.error(
"could not find the peer we created before for this master" 'could not find the peer we created before for this master'
); );
} }
@@ -347,7 +347,7 @@ function StreamRoom({
console.error(error); console.error(error);
toast.error( toast.error(
"Make sure that you have permissions enabled and microphone connected" 'Make sure that you have permissions enabled and microphone connected'
); );
}); });
} }
@@ -368,7 +368,7 @@ function StreamRoom({
useEffect(() => {}, [tunedInUsers]); useEffect(() => {}, [tunedInUsers]);
useEffect(() => { useEffect(() => {
console.log("keeping an eye on user peers map"); console.log('keeping an eye on user peers map');
console.log(userPeers); console.log(userPeers);
}, [userPeers]); }, [userPeers]);
@@ -376,7 +376,7 @@ function StreamRoom({
// TODO: p1...when the peer map user count > tunedIn.length, then we get rid of the right person from list cuzz they have officially left or disconnected // TODO: p1...when the peer map user count > tunedIn.length, then we get rid of the right person from list cuzz they have officially left or disconnected
useEffect(() => { useEffect(() => {
console.log("change in tuned in users in the streaming room!!!"); console.log('change in tuned in users in the streaming room!!!');
setUserPeers((prevUserPeersMap) => { setUserPeers((prevUserPeersMap) => {
// go through the userIds here // go through the userIds here
@@ -389,7 +389,7 @@ function StreamRoom({
otherUserIdsPeers.forEach((otherUserId) => { otherUserIdsPeers.forEach((otherUserId) => {
// problem if we are trying to show stream of someone who is not tuned in // problem if we are trying to show stream of someone who is not tuned in
if (!tunedInUsers.includes(otherUserId)) { if (!tunedInUsers.includes(otherUserId)) {
console.log("user left with id:", otherUserId); console.log('user left with id:', otherUserId);
const disconnectedLocalPeer = newMap[otherUserId]; const disconnectedLocalPeer = newMap[otherUserId];
if (disconnectedLocalPeer) { if (disconnectedLocalPeer) {
@@ -436,9 +436,9 @@ function PeerStreamRenderer({
const streamRef = useRef<HTMLVideoElement>(null); const streamRef = useRef<HTMLVideoElement>(null);
useEffect(() => { useEffect(() => {
peer.on("stream", (remotePeerStream: MediaStream) => { peer.on('stream', (remotePeerStream: MediaStream) => {
console.log( console.log(
"stream coming in from remote peer...BUT, only going to show once they broadcast" 'stream coming in from remote peer...BUT, only going to show once they broadcast'
); );
if (streamRef?.current) streamRef.current.srcObject = remotePeerStream; if (streamRef?.current) streamRef.current.srcObject = remotePeerStream;
@@ -1,9 +1,9 @@
import NirvanaApi, { ApiCalls } from "./nirvanaApi"; import NirvanaApi, { ApiCalls } from './nirvanaApi';
import { useMutation, useQuery } from "react-query"; import { useMutation, useQuery } from 'react-query';
import { $jwtToken } from "./recoil"; import { $jwtToken } from './recoil';
import { queryClient } from "../pages/nirvanaApp"; import { queryClient } from '../../legacy/nirvanaApp';
import { useRecoilValue } from "recoil"; import { useRecoilValue } from 'recoil';
// ====== QUERIES // ====== QUERIES
@@ -11,7 +11,7 @@ import { useRecoilValue } from "recoil";
* ensure that the server is up * ensure that the server is up
*/ */
export function useServerCheck() { export function useServerCheck() {
return useQuery("SERVER_CHECK", ApiCalls.serverCheck, { return useQuery('SERVER_CHECK', ApiCalls.serverCheck, {
retry: true, retry: true,
refetchOnWindowFocus: false, refetchOnWindowFocus: false,
@@ -22,7 +22,7 @@ export function useServerCheck() {
export function useAuthCheck(enabled: boolean = true) { export function useAuthCheck(enabled: boolean = true) {
const jwtToken = useRecoilValue($jwtToken); const jwtToken = useRecoilValue($jwtToken);
return useQuery("AUTH_CHECK", ApiCalls.authCheck, { return useQuery('AUTH_CHECK', ApiCalls.authCheck, {
retry: false, retry: false,
refetchOnWindowFocus: false, refetchOnWindowFocus: false,
@@ -32,11 +32,11 @@ export function useAuthCheck(enabled: boolean = true) {
} }
export function useLogin() { export function useLogin() {
return useMutation("LOGIN", ApiCalls.login, {}); return useMutation('LOGIN', ApiCalls.login, {});
} }
export function useGetUserDetails() { export function useGetUserDetails() {
return useQuery("USER_DETAILS", ApiCalls.getUserDetails, { return useQuery('USER_DETAILS', ApiCalls.getUserDetails, {
retry: false, retry: false,
refetchOnWindowFocus: false, refetchOnWindowFocus: false,
onError: (err) => { onError: (err) => {
@@ -46,7 +46,7 @@ export function useGetUserDetails() {
} }
export function useUserSearch(searchQuery: string) { export function useUserSearch(searchQuery: string) {
return useQuery("USER_SEARCH", () => ApiCalls.userSearch(searchQuery), { return useQuery('USER_SEARCH', () => ApiCalls.userSearch(searchQuery), {
enabled: searchQuery ? true : false, enabled: searchQuery ? true : false,
refetchOnWindowFocus: false, refetchOnWindowFocus: false,
}); });
@@ -57,7 +57,7 @@ export function useUserLines() {
// todo: base/source of truth for getting all of the lines for the user // todo: base/source of truth for getting all of the lines for the user
// merge with sockets + audio clip data + master data + convomember data // merge with sockets + audio clip data + master data + convomember data
return useQuery("USER_LINES", ApiCalls.getUserLines, { return useQuery('USER_LINES', ApiCalls.getUserLines, {
refetchOnWindowFocus: false, refetchOnWindowFocus: false,
refetchIntervalInBackground: false, refetchIntervalInBackground: false,
staleTime: Infinity, staleTime: Infinity,
@@ -72,7 +72,7 @@ export function useGetDmByUserId() {
export function useCreateLine() { export function useCreateLine() {
return useMutation(ApiCalls.createLine, { return useMutation(ApiCalls.createLine, {
onSuccess: (res, req) => { onSuccess: (res, req) => {
queryClient.invalidateQueries(["USER_LINES"]); queryClient.invalidateQueries(['USER_LINES']);
}, },
}); });
} }
@@ -1,4 +1,4 @@
import { $desktopMode, $jwtToken, $selectedLineId } from "./recoil"; import { $desktopMode, $jwtToken, $selectedLineId } from './recoil';
import { import {
ConnectToLineRequest, ConnectToLineRequest,
ServerRequestChannels, ServerRequestChannels,
@@ -12,18 +12,18 @@ import {
UntuneFromLineRequest, UntuneFromLineRequest,
UserStartedBroadcastingResponse, UserStartedBroadcastingResponse,
UserStoppedBroadcastingResponse, UserStoppedBroadcastingResponse,
} from "@nirvana/core/sockets/channels"; } from '@nirvana/core/sockets/channels';
import React, { useContext, useState } from "react"; import React, { useContext, useState } from 'react';
import { Socket, io } from "socket.io-client"; import { Socket, io } from 'socket.io-client';
import { useCallback, useEffect } from "react"; import { useCallback, useEffect } from 'react';
import { useRecoilValue, useSetRecoilState } from "recoil"; import { useRecoilValue, useSetRecoilState } from 'recoil';
import { LineMemberState } from "@nirvana/core/models/line.model"; import { LineMemberState } from '@nirvana/core/models/line.model';
import MasterLineData from "@nirvana/core/models/masterLineData.model"; import MasterLineData from '@nirvana/core/models/masterLineData.model';
import { User } from "@nirvana/core/models"; import { User } from '@nirvana/core/models';
import { queryClient } from "../pages/nirvanaApp"; import { queryClient } from '../../legacy/nirvanaApp';
import toast from "react-hot-toast"; import toast from 'react-hot-toast';
import { useUserLines } from "./index"; import { useUserLines } from './index';
let $ws: Socket; let $ws: Socket;
@@ -44,19 +44,19 @@ function useSocketHandler(linesData: MasterLineData[]) {
// https://socket.io/docs/v4/client-options/#reconnection // https://socket.io/docs/v4/client-options/#reconnection
useEffect(() => { useEffect(() => {
$ws = io("http://localhost:5000", { $ws = io('http://localhost:5000', {
query: { token: jwtToken }, query: { token: jwtToken },
transports: ["websocket"], transports: ['websocket'],
upgrade: false, upgrade: false,
forceNew: true, forceNew: true,
reconnection: false, // ! TESTING THE PROBLEM WITH RECONNECTION CLIENT LISTENERS NOT ACTIVATING reconnection: false, // ! TESTING THE PROBLEM WITH RECONNECTION CLIENT LISTENERS NOT ACTIVATING
}); });
$ws.on("connect", () => { $ws.on('connect', () => {
console.log( console.log(
"SOCKETS | CLIENT CONNECTED in socket handler, setting up client side listeners for requests" 'SOCKETS | CLIENT CONNECTED in socket handler, setting up client side listeners for requests'
); );
toast.success("you are connected"); toast.success('you are connected');
/** /**
* initiate listeners * initiate listeners
@@ -160,7 +160,7 @@ function useSocketHandler(linesData: MasterLineData[]) {
$ws.on( $ws.on(
ServerResponseChannels.SOMEONE_STARTED_BROADCASTING, ServerResponseChannels.SOMEONE_STARTED_BROADCASTING,
(res: UserStartedBroadcastingResponse) => { (res: UserStartedBroadcastingResponse) => {
console.log("someone is starting to broadcast"); console.log('someone is starting to broadcast');
setLinesMap((prevLinesMap) => { setLinesMap((prevLinesMap) => {
const newMap = { ...prevLinesMap }; const newMap = { ...prevLinesMap };
@@ -198,28 +198,28 @@ function useSocketHandler(linesData: MasterLineData[]) {
// on disconnections, just switch it to flow state? // on disconnections, just switch it to flow state?
// what if there was another problem? // what if there was another problem?
$ws.io.on("close", () => { $ws.io.on('close', () => {
console.error( console.error(
"SOCKET | there was a problem with your app...connection closed likely due to idling or manual disconnect" 'SOCKET | there was a problem with your app...connection closed likely due to idling or manual disconnect'
); );
// todo: figure out the right thing based on the situation whether it's a problem or user unplugs // todo: figure out the right thing based on the situation whether it's a problem or user unplugs
// toast( // toast(
// "Disconnected due to idling or some other issue. Please reconnect or refresh to fix the problem." // "Disconnected due to idling or some other issue. Please reconnect or refresh to fix the problem."
// ); // );
toast("unplugging"); toast('unplugging');
setDesktopMode("flowState"); setDesktopMode('flowState');
}); });
// client-side errors // client-side errors
$ws.on("connect_error", (err) => { $ws.on('connect_error', (err) => {
console.error(`SOCKETS | ${err.message}`); // prints the message associated with the error console.error(`SOCKETS | ${err.message}`); // prints the message associated with the error
toast.error("sorry...this is our bad...please refresh with cmd + r"); toast.error('sorry...this is our bad...please refresh with cmd + r');
// force refetch of server status as well as these generally go hand in hand // force refetch of server status as well as these generally go hand in hand
// this should overall remount this component currently which is what we want for new data // this should overall remount this component currently which is what we want for new data
queryClient.invalidateQueries("SERVER_CHECK"); queryClient.invalidateQueries('SERVER_CHECK');
}); });
// on unmounting this component, we want to disconnect // on unmounting this component, we want to disconnect
@@ -412,9 +412,9 @@ export function LineDataProvider({ children }) {
// and then disconnect // and then disconnect
useEffect(() => { useEffect(() => {
return () => { return () => {
if (desktopMode === "flowState" && $ws) { if (desktopMode === 'flowState' && $ws) {
console.log( console.log(
"SOCKETS | telling all of my connected rooms that I am unplugging" 'SOCKETS | telling all of my connected rooms that I am unplugging'
); );
$ws.emit(ServerRequestChannels.GOING_INTO_FLOW_STATE); $ws.emit(ServerRequestChannels.GOING_INTO_FLOW_STATE);
@@ -1,58 +1,58 @@
import { atom } from "recoil"; import { atom } from 'recoil';
export const $searchQuery = atom<string>({ export const $searchQuery = atom<string>({
key: "SEARCH_QUERY", key: 'SEARCH_QUERY',
default: "", default: '',
}); });
export const $jwtToken = atom<string>({ export const $jwtToken = atom<string>({
key: "JWT_TOKEN", key: 'JWT_TOKEN',
default: null, default: null,
}); });
// conversation id // conversation id
export const $selectedConversation = atom<string>({ export const $selectedConversation = atom<string>({
key: "SELECTED_CONVERSATION", key: 'SELECTED_CONVERSATION',
default: null, default: null,
}); });
// new convo page trigger // new convo page trigger
export const $newConvoPage = atom<boolean>({ export const $newConvoPage = atom<boolean>({
key: "NEW_CONVO_PAGE", key: 'NEW_CONVO_PAGE',
default: false, default: false,
}); });
// number of active lines // number of active lines
export const $numberActiveLines = atom<number>({ export const $numberActiveLines = atom<number>({
key: "NUMBER_ACTIVE_LINES", key: 'NUMBER_ACTIVE_LINES',
default: 0, default: 0,
}); });
// max number of active streams // max number of active streams
export const $maxNumberActiveStreams = atom<number>({ export const $maxNumberActiveStreams = atom<number>({
key: "MAX_NUMBER_ACTIVE_STREAMS", key: 'MAX_NUMBER_ACTIVE_STREAMS',
default: 0, default: 0,
}); });
// ============ // ============
type DesktopMode = "flowState" | "overlayOnly" | "terminal"; type DesktopMode = 'flowState' | 'overlayOnly' | 'terminal';
export const $desktopMode = atom<DesktopMode>({ export const $desktopMode = atom<DesktopMode>({
key: "DESKTOP_MODE", key: 'DESKTOP_MODE',
default: "terminal", default: 'terminal',
}); });
export const $selectedLineId = atom<string>({ export const $selectedLineId = atom<string>({
key: "SELECTED_LINE_ID", key: 'SELECTED_LINE_ID',
default: null, default: null,
}); });
interface MediaSettings { interface MediaSettings {
mode: "audio" | "video" | "screen"; mode: 'audio' | 'video' | 'screen';
isMuted: boolean; isMuted: boolean;
} }
export const $mediaSettings = atom<MediaSettings>({ export const $mediaSettings = atom<MediaSettings>({
key: "MEDIA_SETTINGS", key: 'MEDIA_SETTINGS',
default: { isMuted: false, mode: "audio" }, default: { isMuted: false, mode: 'audio' },
}); });
@@ -1,21 +1,21 @@
import { useCallback, useEffect, useState } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { LogoType } from '@nirvana/components/logo/full';
import { import {
$desktopMode, $desktopMode,
$maxNumberActiveStreams, $maxNumberActiveStreams,
$numberActiveLines, $numberActiveLines,
$selectedLineId, $selectedLineId,
} from "../../controller/recoil"; } from '../../src/controller/recoil';
import Channels, { import Channels, {
DEFAULT_APP_PRESET, DEFAULT_APP_PRESET,
Dimensions, Dimensions,
} from "../../electron/constants"; } from '../../src/electron/constants';
import { useCallback, useEffect, useState } from "react";
import { useRecoilState, useRecoilValue } from "recoil";
import FullMottoLogo from "../../../../components/logo/fullMotto"; import FullMottoLogo from '@nirvana/components/logo/fullMotto';
import { LineDataProvider } from "../../controller/lineDataProvider"; import { LineDataProvider } from '../../src/controller/lineDataProvider';
import { LogoType } from "@nirvana/components/logo/full"; import NirvanaHeader from '../components/header/index';
import NirvanaHeader from "../../components/header/index"; import NirvanaTerminal from '../terminal';
import NirvanaTerminal from "../terminal";
export default function NirvanaRouter() { export default function NirvanaRouter() {
const [selectedLineId, setSelectedLineId] = useRecoilState($selectedLineId); const [selectedLineId, setSelectedLineId] = useRecoilState($selectedLineId);
@@ -27,16 +27,16 @@ export default function NirvanaRouter() {
useEffect(() => { useEffect(() => {
// add dimensions if it's not overlay only mode // add dimensions if it's not overlay only mode
let finalDimensions: Dimensions = { height: 0, width: 0 }; let finalDimensions: Dimensions = { height: 0, width: 0 };
let finalPosition: "center" | "topRight"; let finalPosition: 'center' | 'topRight';
const setAlwaysOnTop = desktopMode === "overlayOnly"; const setAlwaysOnTop = desktopMode === 'overlayOnly';
// go hunting for which dimensions to have // go hunting for which dimensions to have
if (desktopMode === "terminal" || desktopMode == "flowState") { if (desktopMode === 'terminal' || desktopMode == 'flowState') {
finalDimensions = DEFAULT_APP_PRESET; finalDimensions = DEFAULT_APP_PRESET;
} }
if (desktopMode === "overlayOnly") { if (desktopMode === 'overlayOnly') {
finalDimensions = { finalDimensions = {
height: 68 + numberOfOverlayRows * 200, height: 68 + numberOfOverlayRows * 200,
width: 360 + 360 * numberOfOverlayColumns, width: 360 + 360 * numberOfOverlayColumns,
@@ -44,7 +44,7 @@ export default function NirvanaRouter() {
} }
console.log( console.log(
"setting new dimensions", 'setting new dimensions',
desktopMode, desktopMode,
numberOfOverlayColumns, numberOfOverlayColumns,
numberOfOverlayRows, numberOfOverlayRows,
@@ -70,7 +70,7 @@ export default function NirvanaRouter() {
useEffect(() => { useEffect(() => {
window.electronAPI.on(Channels.ON_WINDOW_BLUR, () => { window.electronAPI.on(Channels.ON_WINDOW_BLUR, () => {
console.log( console.log(
"window blurring now, should be always on top and then ill tell main process to change dimensions" 'window blurring now, should be always on top and then ill tell main process to change dimensions'
); );
// TODO: testing mode... uncomment both instructions below // TODO: testing mode... uncomment both instructions below
// setDesktopMode("overlayOnly"); // setDesktopMode("overlayOnly");
@@ -82,15 +82,15 @@ export default function NirvanaRouter() {
}, [setDesktopMode, setSelectedLineId]); }, [setDesktopMode, setSelectedLineId]);
return ( return (
<div className="flex flex-col flex-1"> <div className='flex flex-col flex-1'>
<NirvanaHeader onHeaderFocus={() => setDesktopMode("terminal")} /> <NirvanaHeader onHeaderFocus={() => setDesktopMode('terminal')} />
{desktopMode === "flowState" && <FlowState />} {desktopMode === 'flowState' && <FlowState />}
{/* remount nirvana terminal */} {/* remount nirvana terminal */}
{(desktopMode === "terminal" || desktopMode === "overlayOnly") && ( {(desktopMode === 'terminal' || desktopMode === 'overlayOnly') && (
<LineDataProvider> <LineDataProvider>
<NirvanaTerminal overlayOnly={desktopMode === "overlayOnly"} /> <NirvanaTerminal overlayOnly={desktopMode === 'overlayOnly'} />
</LineDataProvider> </LineDataProvider>
)} )}
</div> </div>
@@ -109,7 +109,7 @@ function FlowState() {
const [quote, setQuote] = useState<Quote>(null); const [quote, setQuote] = useState<Quote>(null);
useEffect(() => { useEffect(() => {
fetch("https://api.quotable.io/random") fetch('https://api.quotable.io/random')
.then((res) => res.json()) .then((res) => res.json())
.then((data: Quote) => { .then((data: Quote) => {
console.warn(data); console.warn(data);
@@ -123,19 +123,19 @@ function FlowState() {
}, []); }, []);
return ( return (
<div className="flex flex-col flex-1 justify-center items-center relative"> <div className='flex flex-col flex-1 justify-center items-center relative'>
{/* <img src="https://source.unsplash.com/random/?nature" /> */} {/* <img src="https://source.unsplash.com/random/?nature" /> */}
<FullMottoLogo <FullMottoLogo
type={LogoType.small} type={LogoType.small}
className={"absolute bottom-2 mx-auto"} className='absolute bottom-2 mx-auto'
/> />
{quote && ( {quote && (
<span className="flex flex-col justify-center items-center max-w-screen-sm"> <span className='flex flex-col justify-center items-center max-w-screen-sm'>
<span className="text-xl text-gray-800 font-semibold text-center"> <span className='text-xl text-gray-800 font-semibold text-center'>
"{quote.content}" "{quote.content}"
</span> </span>
<span className="tex-md italic text-gray-400">{quote.author}</span> <span className='tex-md italic text-gray-400'>{quote.author}</span>
</span> </span>
)} )}
</div> </div>
@@ -1,19 +1,19 @@
import { $desktopMode, $selectedLineId } from "../../controller/recoil"; import { $desktopMode, $selectedLineId } from '../../src/controller/recoil';
import { Avatar, Skeleton, Tooltip } from "antd"; import { Avatar, Skeleton, Tooltip } from 'antd';
import { FiActivity, FiHeadphones, FiSettings, FiSun } from "react-icons/fi"; import { FiActivity, FiHeadphones, FiSettings, FiSun } from 'react-icons/fi';
import { GlobalHotKeys, KeyMap } from "react-hotkeys"; import { GlobalHotKeys, KeyMap } from 'react-hotkeys';
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useMemo, useState } from 'react';
import { useGetUserDetails, useUserLines } from "../../controller/index"; import { useGetUserDetails, useUserLines } from '../../src/controller/index';
import { useRecoilState, useSetRecoilState } from "recoil"; import { useRecoilState, useSetRecoilState } from 'recoil';
import { FaPlus } from "react-icons/fa"; import { FaPlus } from 'react-icons/fa';
import LineIcon from "../../components/lines/lineIcon/index"; import LineIcon from '../components/lines/lineIcon/index';
import { LineMemberState } from "@nirvana/core/models/line.model"; import { LineMemberState } from '@nirvana/core/models/line.model';
import LineRow from "../../components/lines/lineRow.tsx/index"; import LineRow from '../components/lines/lineRow.tsx/index';
import MasterLineData from "@nirvana/core/models/masterLineData.model"; import MasterLineData from '@nirvana/core/models/masterLineData.model';
import NewLineModal from "./newLine"; import NewLineModal from './newLine';
import toast from "react-hot-toast"; import toast from 'react-hot-toast';
import { useLineDataProvider } from "../../controller/lineDataProvider"; import { useLineDataProvider } from '../../src/controller/lineDataProvider';
/** /**
* Socket Provider * Socket Provider
@@ -93,7 +93,7 @@ export default function NirvanaTerminal({
// todo: sort/order based on activity and activity date and currently broadcasting/live // todo: sort/order based on activity and activity date and currently broadcasting/live
const handleEscape = useCallback(() => { const handleEscape = useCallback(() => {
console.log("deselecting line"); console.log('deselecting line');
setSelectedLineId((prevSelectedLineId) => { setSelectedLineId((prevSelectedLineId) => {
// ! only want to untune if it's a temporarily tuned line // ! only want to untune if it's a temporarily tuned line
@@ -128,7 +128,7 @@ export default function NirvanaTerminal({
(lineId: string, turnToggleOn: boolean) => { (lineId: string, turnToggleOn: boolean) => {
// inhibit if they are trying to turn on and already have 3 toggle tuned // inhibit if they are trying to turn on and already have 3 toggle tuned
if (toggleTunedLines?.length >= 3 && turnToggleOn) { if (toggleTunedLines?.length >= 3 && turnToggleOn) {
toast.error("You cannot toggle more than 3 lines!"); toast.error('You cannot toggle more than 3 lines!');
return; return;
} }
@@ -162,14 +162,14 @@ export default function NirvanaTerminal({
const keyMap: KeyMap = useMemo( const keyMap: KeyMap = useMemo(
() => ({ () => ({
DESELECT_LINE: "esc", DESELECT_LINE: 'esc',
START_BROADCAST: { START_BROADCAST: {
sequence: "`", sequence: '`',
action: "keydown", action: 'keydown',
}, },
STOP_BROADCAST: { STOP_BROADCAST: {
sequence: "`", sequence: '`',
action: "keyup", action: 'keyup',
}, },
}), }),
[] []
@@ -188,8 +188,8 @@ export default function NirvanaTerminal({
<> <>
<GlobalHotKeys handlers={handlers} keyMap={keyMap} allowChanges /> <GlobalHotKeys handlers={handlers} keyMap={keyMap} allowChanges />
<div className="flex flex-row flex-1"> <div className='flex flex-row flex-1'>
<div className="flex flex-col bg-white w-[400px] relative group"> <div className='flex flex-col bg-white w-[400px] relative group'>
{/* modal for creating new line */} {/* modal for creating new line */}
<NewLineModal <NewLineModal
open={isModalVisible} open={isModalVisible}
@@ -197,17 +197,17 @@ export default function NirvanaTerminal({
/> />
{/* tuned in lines block */} {/* tuned in lines block */}
<div className="bg-gray-100 flex flex-col shadow-lg"> <div className='bg-gray-100 flex flex-col shadow-lg'>
{/* tuned in header + general controls */} {/* tuned in header + general controls */}
<Tooltip placement="right" title={"These are your active rooms..."}> <Tooltip placement='right' title={'These are your active rooms...'}>
<div className="flex flex-row items-center py-3 px-4 pb-0"> <div className='flex flex-row items-center py-3 px-4 pb-0'>
<span className="flex flex-row gap-2 items-center justify-start text-gray-400 animate-pulse"> <span className='flex flex-row gap-2 items-center justify-start text-gray-400 animate-pulse'>
<FiActivity className="text-sm" /> <FiActivity className='text-sm' />
<h2 className="text-inherit text-sm">Rooms</h2> <h2 className='text-inherit text-sm'>Rooms</h2>
<p className="text-slate-300 text-xs">{`${ <p className='text-slate-300 text-xs'>{`${
toggleTunedLines?.length || 0 toggleTunedLines?.length || 0
}/3`}</p> }/3`}</p>
</span> </span>
@@ -215,7 +215,7 @@ export default function NirvanaTerminal({
</Tooltip> </Tooltip>
{/* list of toggle tuned lines */} {/* list of toggle tuned lines */}
<div className="flex flex-col mt-2"> <div className='flex flex-col mt-2'>
{toggleTunedLines.map((masterLineData) => ( {toggleTunedLines.map((masterLineData) => (
<LineRow <LineRow
key={`terminalListLines-${masterLineData.lineDetails._id.toString()}`} key={`terminalListLines-${masterLineData.lineDetails._id.toString()}`}
@@ -227,14 +227,14 @@ export default function NirvanaTerminal({
</div> </div>
{!(allLines.length > 0) && !(toggleTunedLines.length > 0) && ( {!(allLines.length > 0) && !(toggleTunedLines.length > 0) && (
<span className="text-gray-300 text-sm my-5 text-center"> <span className='text-gray-300 text-sm my-5 text-center'>
You have no lines! <br /> Create one to connect to your team You have no lines! <br /> Create one to connect to your team
instantly. instantly.
</span> </span>
)} )}
{/* rest of the lines */} {/* rest of the lines */}
<div className={"flex flex-col"}> <div className={'flex flex-col'}>
{isLoadingInitialLines ? ( {isLoadingInitialLines ? (
<Skeleton /> <Skeleton />
) : ( ) : (
@@ -250,12 +250,12 @@ export default function NirvanaTerminal({
<div <div
onClick={() => setIsModalVisible(true)} onClick={() => setIsModalVisible(true)}
className="absolute bottom-3 right-3 z-10 scale-0 className='absolute bottom-3 right-3 z-10 scale-0
group-hover:scale-100 ease-in-out hover:transition group-hover:transition delay-100 duration-200" group-hover:scale-100 ease-in-out hover:transition group-hover:transition delay-100 duration-200'
> >
<button <button
className="flex flex-row gap-2 items-center justify-evenly className='flex flex-row gap-2 items-center justify-evenly
shadow-xl bg-gray-800 p-2 text-white text-xs" shadow-xl bg-gray-800 p-2 text-white text-xs'
> >
<FaPlus /> <FaPlus />
<span>New line</span> <span>New line</span>
@@ -270,13 +270,13 @@ export default function NirvanaTerminal({
/> />
) : ( ) : (
<div <div
className="flex flex-col flex-1 justify-center items-center bg-gray-100 className='flex flex-col flex-1 justify-center items-center bg-gray-100
border-l border-l-gray-200" border-l border-l-gray-200'
> >
<span className="text-xl text-gray-800"> <span className='text-xl text-gray-800'>
{`Hi ${userDetails?.user?.givenName}!`} {`Hi ${userDetails?.user?.givenName}!`}
</span> </span>
<span className="text-md text-gray-400">You're all set!</span> <span className='text-md text-gray-400'>You're all set!</span>
</div> </div>
)} )}
</div> </div>
@@ -293,7 +293,7 @@ function LineDetailsTerminal({
}) { }) {
const { data: userDetails } = useGetUserDetails(); const { data: userDetails } = useGetUserDetails();
console.log("selected line", selectedLine); console.log('selected line', selectedLine);
const isUserToggleTuned = useMemo( const isUserToggleTuned = useMemo(
() => selectedLine?.currentUserMember?.state === LineMemberState.TUNED, () => selectedLine?.currentUserMember?.state === LineMemberState.TUNED,
@@ -357,20 +357,20 @@ function LineDetailsTerminal({
return ( return (
<div <div
className="flex flex-col flex-1 bg-gray-100 className='flex flex-col flex-1 bg-gray-100
border-l border-l-gray-200 relative" border-l border-l-gray-200 relative'
> >
{/* line details */} {/* line details */}
<div <div
className="p-4 className='p-4
flex flex-row items-center gap-2 justify-end border-b-gray-200 border-b" flex flex-row items-center gap-2 justify-end border-b-gray-200 border-b'
> >
{profilePictures && ( {profilePictures && (
<LineIcon grayscale={false} sourceImages={profilePictures} /> <LineIcon grayscale={false} sourceImages={profilePictures} />
)} )}
<div className="flex flex-col items-start mr-auto group"> <div className='flex flex-col items-start mr-auto group'>
<span className="flex flex-row gap-2 items-center"> <span className='flex flex-row gap-2 items-center'>
<h2 className={`text-lg text-slate-800 font-semibold`}> <h2 className={`text-lg text-slate-800 font-semibold`}>
{selectedLine.lineDetails.name || {selectedLine.lineDetails.name ||
selectedLine.otherUserObjects[0].givenName} selectedLine.otherUserObjects[0].givenName}
@@ -380,16 +380,16 @@ function LineDetailsTerminal({
className={`p-1 hidden group-hover:flex justify-center items-center hover:bg-gray-300 className={`p-1 hidden group-hover:flex justify-center items-center hover:bg-gray-300
transition-all hover:scale-105`} transition-all hover:scale-105`}
> >
<FiSettings className="text-gray-400 text-xs" /> <FiSettings className='text-gray-400 text-xs' />
</button> </button>
</span> </span>
<span className="flex flex-row gap-2 items-center"> <span className='flex flex-row gap-2 items-center'>
<span className="text-gray-300 text-xs">{`${ <span className='text-gray-300 text-xs'>{`${
selectedLine.otherMembers?.length + 1 ?? 0 selectedLine.otherMembers?.length + 1 ?? 0
} members`}</span> } members`}</span>
<span className="h-1 w-1 bg-gray-800 rounded-full"></span> <span className='h-1 w-1 bg-gray-800 rounded-full'></span>
<span className="text-teal-500 text-xs">{`${ <span className='text-teal-500 text-xs'>{`${
selectedLine.tunedInMemberIds?.length ?? 0 selectedLine.tunedInMemberIds?.length ?? 0
} in this room`}</span> } in this room`}</span>
</span> </span>
@@ -397,15 +397,15 @@ function LineDetailsTerminal({
{/* TODO: move to on hover of line row */} {/* TODO: move to on hover of line row */}
<Tooltip <Tooltip
placement="left" placement='left'
title={`${ title={`${
isUserToggleTuned ? "click to untoggle" : "click to stay tuned in" isUserToggleTuned ? 'click to untoggle' : 'click to stay tuned in'
}`} }`}
> >
<button <button
className={`p-2 flex justify-center items-center shadow-lg className={`p-2 flex justify-center items-center shadow-lg
hover:scale-105 transition-all animate-pulse ${ hover:scale-105 transition-all animate-pulse ${
isUserToggleTuned ? "bg-gray-800 text-white" : "text-black" isUserToggleTuned ? 'bg-gray-800 text-white' : 'text-black'
}`} }`}
onClick={() => onClick={() =>
isUserToggleTuned isUserToggleTuned
@@ -419,101 +419,101 @@ function LineDetailsTerminal({
) )
} }
> >
<FiActivity className="text-md" /> <FiActivity className='text-md' />
</button> </button>
</Tooltip> </Tooltip>
</div> </div>
{/* line timeline */} {/* line timeline */}
<div className="flex flex-col items-center gap-2 my-2 mx-auto max-w-lg w-full"> <div className='flex flex-col items-center gap-2 my-2 mx-auto max-w-lg w-full'>
<span <span
className={"text-gray-300 text-sm cursor-pointer hover:underline"} className={'text-gray-300 text-sm cursor-pointer hover:underline'}
> >
load more load more
</span> </span>
<span className={"text-gray-300 text-sm"}>yesterday</span> <span className={'text-gray-300 text-sm'}>yesterday</span>
<div className={"rounded border border-gray-200 flex flex-col w-full"}> <div className={'rounded border border-gray-200 flex flex-col w-full'}>
{selectedLine.otherUserObjects.map((otherUser) => ( {selectedLine.otherUserObjects.map((otherUser) => (
<div <div
className="flex flex-row p-2 gap-2 items-center bg-transparent className='flex flex-row p-2 gap-2 items-center bg-transparent
border-b border-b-gray-200 last:border-b-0" border-b border-b-gray-200 last:border-b-0'
> >
<Avatar <Avatar
key={`linehistory-${1}`} key={`linehistory-${1}`}
src={otherUser.picture} src={otherUser.picture}
shape="square" shape='square'
size={"default"} size={'default'}
// grayscale if not playing? // grayscale if not playing?
className={`${true && "grayscale"}`} className={`${true && 'grayscale'}`}
/> />
<span className="text-gray-500">{otherUser.givenName}</span> <span className='text-gray-500'>{otherUser.givenName}</span>
<span className="ml-auto text-xs text-gray-300">{`${ <span className='ml-auto text-xs text-gray-300'>{`${
Math.floor(Math.random() * 10) + 1 Math.floor(Math.random() * 10) + 1
}:${Math.floor(Math.random() * 100) + 10}pm |`}</span> }:${Math.floor(Math.random() * 100) + 10}pm |`}</span>
<span className="text-gray-400 text-md">{`${ <span className='text-gray-400 text-md'>{`${
Math.floor(Math.random() * 60) + 1 Math.floor(Math.random() * 60) + 1
} seconds`}</span> } seconds`}</span>
</div> </div>
))} ))}
<div <div
className="flex flex-row p-2 gap-2 items-center bg-transparent className='flex flex-row p-2 gap-2 items-center bg-transparent
border-b border-b-gray-200 last:border-b-0" border-b border-b-gray-200 last:border-b-0'
> >
<Avatar <Avatar
key={`linehistory-${1}`} key={`linehistory-${1}`}
src={userDetails.user.picture} src={userDetails.user.picture}
shape="square" shape='square'
size={"default"} size={'default'}
// grayscale if not playing? // grayscale if not playing?
className={`${true && "grayscale"}`} className={`${true && 'grayscale'}`}
/> />
<span className="text-gray-500">{"Arjun Patel"}</span> <span className='text-gray-500'>{'Arjun Patel'}</span>
<span className="ml-auto text-xs text-gray-300">{`${ <span className='ml-auto text-xs text-gray-300'>{`${
Math.floor(Math.random() * 10) + 1 Math.floor(Math.random() * 10) + 1
}:${Math.floor(Math.random() * 100) + 10}pm |`}</span> }:${Math.floor(Math.random() * 100) + 10}pm |`}</span>
<span className="text-gray-400 text-md">{`${ <span className='text-gray-400 text-md'>{`${
Math.floor(Math.random() * 60) + 1 Math.floor(Math.random() * 60) + 1
} seconds`}</span> } seconds`}</span>
</div> </div>
</div> </div>
<span className={"text-gray-300 text-sm"}>today</span> <span className={'text-gray-300 text-sm'}>today</span>
<div <div
className={ className={
"rounded border border-gray-400 flex flex-col w-full shadow-xl" 'rounded border border-gray-400 flex flex-col w-full shadow-xl'
} }
> >
{selectedLine.otherUserObjects.map((otherUser) => ( {selectedLine.otherUserObjects.map((otherUser) => (
// TODO: show the shadow if it's unheard // TODO: show the shadow if it's unheard
<div <div
className="flex flex-row p-2 gap-2 items-center bg-transparent className='flex flex-row p-2 gap-2 items-center bg-transparent
border-b border-b-gray-400 last:border-b-0" border-b border-b-gray-400 last:border-b-0'
> >
<Avatar <Avatar
key={`linehistory-${1}`} key={`linehistory-${1}`}
src={otherUser.picture} src={otherUser.picture}
shape="square" shape='square'
size={"default"} size={'default'}
// grayscale if not playing? // grayscale if not playing?
className={`${false && "grayscale"}`} className={`${false && 'grayscale'}`}
/> />
<span className="text-gray-600 font-semibold"> <span className='text-gray-600 font-semibold'>
{otherUser.name} {otherUser.name}
</span> </span>
<span className="ml-auto text-xs text-gray-400">{`${ <span className='ml-auto text-xs text-gray-400'>{`${
Math.floor(Math.random() * 10) + 1 Math.floor(Math.random() * 10) + 1
}:${Math.floor(Math.random() * 100) + 10}pm |`}</span> }:${Math.floor(Math.random() * 100) + 10}pm |`}</span>
<span className="text-gray-500 text-md">{`${ <span className='text-gray-500 text-md'>{`${
Math.floor(Math.random() * 60) + 1 Math.floor(Math.random() * 60) + 1
} seconds`}</span> } seconds`}</span>
</div> </div>
@@ -522,32 +522,32 @@ function LineDetailsTerminal({
{/* live broadcasters */} {/* live broadcasters */}
<span <span
className={"flex flex-row gap-2 items-center text-teal-500 text-sm"} className={'flex flex-row gap-2 items-center text-teal-500 text-sm'}
> >
<FiSun className="animate-ping" /> <FiSun className='animate-ping' />
<span>right now</span> <span>right now</span>
</span> </span>
<div <div
className={ className={
"rounded border border-teal-500 flex flex-col w-full shadow-2xl" 'rounded border border-teal-500 flex flex-col w-full shadow-2xl'
} }
> >
{selectedLine.otherUserObjects.map((otherUser) => ( {selectedLine.otherUserObjects.map((otherUser) => (
<div className="flex flex-row p-2 gap-2 items-center bg-transparent"> <div className='flex flex-row p-2 gap-2 items-center bg-transparent'>
<Avatar <Avatar
key={`linehistory-${1}`} key={`linehistory-${1}`}
src={otherUser.picture} src={otherUser.picture}
shape="square" shape='square'
size={"large"} size={'large'}
// grayscale if not playing? // grayscale if not playing?
className={`shadow-lg`} className={`shadow-lg`}
/> />
<span className="text-gray-600 font-semibold"> <span className='text-gray-600 font-semibold'>
{otherUser.name} {otherUser.name}
</span> </span>
<Tooltip title={"audio only"}> <Tooltip title={'audio only'}>
<FiHeadphones className="text-gray-600 text-md ml-auto" /> <FiHeadphones className='text-gray-600 text-md ml-auto' />
</Tooltip> </Tooltip>
</div> </div>
))} ))}
@@ -558,11 +558,11 @@ function LineDetailsTerminal({
className={`p-3 absolute right-3 bottom-3 flex justify-center items-center shadow-2xl className={`p-3 absolute right-3 bottom-3 flex justify-center items-center shadow-2xl
hover:scale-105 transition-all ${ hover:scale-105 transition-all ${
isUserBroadcasting isUserBroadcasting
? "bg-teal-800 text-white" ? 'bg-teal-800 text-white'
: "text-teal-800 border-teal-800 border" : 'text-teal-800 border-teal-800 border'
}`} }`}
> >
<FiSun className="text-lg" /> <FiSun className='text-lg' />
</button> </button>
</div> </div>
); );
@@ -1,12 +1,12 @@
import { Avatar, Modal } from "antd"; import { Avatar, Modal } from 'antd';
import { HotKeys, KeyMap } from "react-hotkeys"; import { HotKeys, KeyMap } from 'react-hotkeys';
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from 'react';
import { useCreateLine, useUserSearch } from "../../../controller/index"; import { useCreateLine, useUserSearch } from '../../../src/controller/index';
import BasicUserRow from "../../../components/User/basicUserDetailsRow"; import BasicUserRow from '../../components/User/basicUserDetailsRow';
import { FiSearch } from "react-icons/fi"; import { FiSearch } from 'react-icons/fi';
import { User } from "@nirvana/core/models"; import { User } from '@nirvana/core/models';
import toast from "react-hot-toast"; import toast from 'react-hot-toast';
export default function NewLineModal({ export default function NewLineModal({
open, open,
@@ -17,25 +17,25 @@ export default function NewLineModal({
}) { }) {
const [selectedPeople, setSelectedPeople] = useState<User[]>([]); const [selectedPeople, setSelectedPeople] = useState<User[]>([]);
const [peopleSearchValue, setPeopleSearchValue] = useState<string>(""); const [peopleSearchValue, setPeopleSearchValue] = useState<string>('');
// the actual state that goes to query...the debounced one so to speak // the actual state that goes to query...the debounced one so to speak
const [searchQuery, setSearchQuery] = useState<string>(""); const [searchQuery, setSearchQuery] = useState<string>('');
const { refetch, data: searchRes } = useUserSearch(searchQuery); const { refetch, data: searchRes } = useUserSearch(searchQuery);
const { mutateAsync, isLoading } = useCreateLine(); const { mutateAsync, isLoading } = useCreateLine();
const [lineName, setLineName] = useState<string>(""); const [lineName, setLineName] = useState<string>('');
useEffect(() => { useEffect(() => {
if (searchQuery) refetch(); if (searchQuery) refetch();
}, [searchQuery]); }, [searchQuery]);
const onSearch = useCallback(() => { const onSearch = useCallback(() => {
console.log("enter key pressed"); console.log('enter key pressed');
if (peopleSearchValue) { if (peopleSearchValue) {
console.log("searching for people in database"); console.log('searching for people in database');
setSearchQuery(peopleSearchValue); setSearchQuery(peopleSearchValue);
} }
}, [setSearchQuery, peopleSearchValue]); }, [setSearchQuery, peopleSearchValue]);
@@ -52,7 +52,7 @@ export default function NewLineModal({
return [...prevSelectedUsers, userToAdd]; return [...prevSelectedUsers, userToAdd];
} }
toast.error("you already selected this person below!"); toast.error('you already selected this person below!');
return prevSelectedUsers; return prevSelectedUsers;
}); });
}, },
@@ -78,11 +78,11 @@ export default function NewLineModal({
// make sure that the list of lines updates for this client and others so that it shows this new line // make sure that the list of lines updates for this client and others so that it shows this new line
// select the line so that it shows up in the line details for this client // select the line so that it shows up in the line details for this client
console.log("trying to create line now!"); console.log('trying to create line now!');
try { try {
if (!selectedPeople?.length) { if (!selectedPeople?.length) {
toast.error("you must select at least one person"); toast.error('you must select at least one person');
return; return;
} }
@@ -95,7 +95,7 @@ export default function NewLineModal({
otherMemberIds: selectedMemberIds, otherMemberIds: selectedMemberIds,
}); });
toast.success("created line!"); toast.success('created line!');
// handle close once the new line is created // handle close once the new line is created
handleClose(); handleClose();
@@ -103,7 +103,7 @@ export default function NewLineModal({
toast.error(error); toast.error(error);
console.error(error); console.error(error);
} finally { } finally {
console.log("done"); console.log('done');
} }
}, [lineName, selectedPeople]); }, [lineName, selectedPeople]);
@@ -112,7 +112,7 @@ export default function NewLineModal({
}; };
const keyMap: KeyMap = { const keyMap: KeyMap = {
HANDLE_SEARCH: "enter", HANDLE_SEARCH: 'enter',
}; };
const handlers = { const handlers = {
HANDLE_SEARCH: onSearch, HANDLE_SEARCH: onSearch,
@@ -123,49 +123,49 @@ export default function NewLineModal({
return ( return (
<> <>
<Modal <Modal
title="Create a Line" title='Create a Line'
visible={open} visible={open}
onCancel={handleCancel} onCancel={handleCancel}
footer={ footer={
<div className="flex flex-row text-white"> <div className='flex flex-row text-white'>
<button <button
className="flex-1 bg-gray-500 pb-3 pt-2 text-left pl-2" className='flex-1 bg-gray-500 pb-3 pt-2 text-left pl-2'
onClick={handleCancel} onClick={handleCancel}
> >
Cancel Cancel
</button> </button>
<button <button
className="flex-1 bg-teal-500 pb-3 pt-2 text-left pl-2" className='flex-1 bg-teal-500 pb-3 pt-2 text-left pl-2'
onClick={handleSubmit} onClick={handleSubmit}
> >
Connect Connect
</button> </button>
</div> </div>
} }
className={"flex flex-col gap-5"} className={'flex flex-col gap-5'}
> >
<HotKeys handlers={handlers} keyMap={keyMap} allowChanges={true}> <HotKeys handlers={handlers} keyMap={keyMap} allowChanges={true}>
<div className="flex flex-col items-start gap-2 mb-5"> <div className='flex flex-col items-start gap-2 mb-5'>
<p className="text-gray-300 text-sm">People</p> <p className='text-gray-300 text-sm'>People</p>
<span className="flex flex-row gap-1 w-full items-center border border-gray-200 p-2 shadow"> <span className='flex flex-row gap-1 w-full items-center border border-gray-200 p-2 shadow'>
<FiSearch className="text-gray-300" /> <FiSearch className='text-gray-300' />
<input <input
className="placeholder:text-gray-300 outline-none placeholder:text-sm border-0 flex-1" className='placeholder:text-gray-300 outline-none placeholder:text-sm border-0 flex-1'
value={peopleSearchValue} value={peopleSearchValue}
onChange={(e) => setPeopleSearchValue(e.target.value)} onChange={(e) => setPeopleSearchValue(e.target.value)}
placeholder="search by name or email" placeholder='search by name or email'
/> />
<span className="text-xs text-gray-200 ml-auto"> <span className='text-xs text-gray-200 ml-auto'>
enter to search enter to search
</span> </span>
</span> </span>
{/* search results */} {/* search results */}
{searchRes?.users?.length > 0 && ( {searchRes?.users?.length > 0 && (
<div className="flex flex-col border border-gray-200 shadow-md max-h-[500px] w-full overflow-y-auto"> <div className='flex flex-col border border-gray-200 shadow-md max-h-[500px] w-full overflow-y-auto'>
{searchRes?.users?.map((searchedUser) => ( {searchRes?.users?.map((searchedUser) => (
<BasicUserRow <BasicUserRow
key={`searchResUser-${searchedUser.googleId}`} key={`searchResUser-${searchedUser.googleId}`}
@@ -183,10 +183,10 @@ export default function NewLineModal({
{/* selected people */} {/* selected people */}
{selectedPeople?.length > 0 && ( {selectedPeople?.length > 0 && (
<div className="flex flex-col gap-2 mb-5"> <div className='flex flex-col gap-2 mb-5'>
<p className="text-gray-300 text-sm">Selected People</p> <p className='text-gray-300 text-sm'>Selected People</p>
<div className="flex flex-col w-full"> <div className='flex flex-col w-full'>
{selectedPeople.map((selectedUser) => ( {selectedPeople.map((selectedUser) => (
<BasicUserRow <BasicUserRow
key={`selectedUser-${selectedUser.googleId}`} key={`selectedUser-${selectedUser.googleId}`}
@@ -206,14 +206,14 @@ export default function NewLineModal({
</div> </div>
)} )}
<div className="flex flex-col gap-2"> <div className='flex flex-col gap-2'>
<p className="text-gray-300 text-sm">Line Name (optional)</p> <p className='text-gray-300 text-sm'>Line Name (optional)</p>
<input <input
value={lineName} value={lineName}
onChange={(e) => setLineName(e.target.value)} onChange={(e) => setLineName(e.target.value)}
className="placeholder:text-gray-300 outline-none placeholder:text-sm flex-1 className='placeholder:text-gray-300 outline-none placeholder:text-sm flex-1
border p-2 border-gray-200" border p-2 border-gray-200'
placeholder={"ex. Engineering, Sprint 7, Follow up on present..."} placeholder={'ex. Engineering, Sprint 7, Follow up on present...'}
/> />
</div> </div>
</HotKeys> </HotKeys>
+710 -653
View File
File diff suppressed because it is too large Load Diff