Skip to content

Commit

Permalink
[Feat] BluetoothConnectionOptions
Browse files Browse the repository at this point in the history
Created a button which opens a dialog for bluetooth device choice.
References #24, #27.
  • Loading branch information
angel-penchev committed Oct 26, 2021
1 parent 5431048 commit 1f00bf2
Show file tree
Hide file tree
Showing 21 changed files with 296 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React, { lazy, Suspense } from 'react';

const LazyBluetoothConnectDialog = lazy(
() => import('./BluetoothConnectDialog'),
);

const BluetoothConnectDialog = (
props: JSX.IntrinsicAttributes & { children?: React.ReactNode },
) => (
<Suspense fallback={null}>
<LazyBluetoothConnectDialog {...props} />
</Suspense>
);

export default BluetoothConnectDialog;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.BluetoothConnectDialog {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/* eslint-disable */
import BluetoothConnectDialog from './BluetoothConnectDialog';

export default {
title: "BluetoothConnectDialog",
};

export const Default = () => <BluetoothConnectDialog />;

Default.story = {
name: 'default',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import BluetoothConnectDialog from './BluetoothConnectDialog';

describe('<BluetoothConnectDialog />', () => {
test('it should mount', () => {
render(<BluetoothConnectDialog />);

const bluetoothConnectDialog = screen.getByTestId('BluetoothConnectDialog');

expect(bluetoothConnectDialog).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Container, Dialog, DialogTitle } from '@mui/material';
import React, { FC, useEffect, useState } from 'react';
import styles from './BluetoothConnectDialog.module.scss';
import BluetoothDeviceSelection from '../BluetoothDeviceSelection/BluetoothDeviceSelection';
import UnsupportedPlatform from '../UnsupportedPlatform/UnsupportedPlatform';

interface BluetoothConnectDialogProps {
open: boolean;
onClose: (device: BluetoothDevice) => void;
}

const BluetoothConnectDialog: FC<BluetoothConnectDialogProps> = (
props: BluetoothConnectDialogProps,
) => {
const { onClose, open } = props;
const [supportsBluetooth, setSupportsBluetooth] = useState(false);

useEffect(() => {
if (navigator.bluetooth) {
navigator.bluetooth
.getAvailability()
.then((isAvailable) => setSupportsBluetooth(isAvailable))
.catch(() => setSupportsBluetooth(false));
}
}, []);

const handleClose = (device: BluetoothDevice) => {
onClose(device);
};

return (
<Container
className={styles.BluetoothConnectDialog}
data-testid="BluetoothConnectDialog"
>
<Dialog fullWidth={true} onClose={handleClose} open={open}>
<DialogTitle>Connect to headset</DialogTitle>
{supportsBluetooth ? (
<BluetoothDeviceSelection handleDeviceClick={handleClose} />
) : (
<UnsupportedPlatform />
)}
</Dialog>
</Container>
);
};

export default BluetoothConnectDialog;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React, { lazy, Suspense } from 'react';

const LazyBluetoothConnectionOptions = lazy(() => import('./BluetoothConnectionOptions'));

const BluetoothConnectionOptions = (props: JSX.IntrinsicAttributes & { children?: React.ReactNode; }) => (
<Suspense fallback={null}>
<LazyBluetoothConnectionOptions {...props} />
</Suspense>
);

export default BluetoothConnectionOptions;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.BluetoothConnectionOptions {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/* eslint-disable */
import BluetoothConnectionOptions from './BluetoothConnectionOptions';

export default {
title: "BluetoothConnectionOptions",
};

export const Default = () => <BluetoothConnectionOptions />;

Default.story = {
name: 'default',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import BluetoothConnectionOptions from './BluetoothConnectionOptions';

describe('<BluetoothConnectionOptions />', () => {
test('it should mount', () => {
render(<BluetoothConnectionOptions />);

const bluetoothConnectionOptions = screen.getByTestId('BluetoothConnectionOptions');

expect(bluetoothConnectionOptions).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React, { FC, useContext } from 'react';
import { Button, Container } from '@mui/material';
import styles from './BluetoothConnectionOptions.module.scss';
import { BluetoothSearching, BluetoothDisabled } from '@mui/icons-material';
import BluetoothConnectDialog from '../BluetoothConnectDialog/BluetoothConnectDialog';
import { HeadsetContext } from '../../contexts/HeadsetContext';

const BluetoothConnectionOptions: FC<{}> = () => {
const { headset, setHeadset } = useContext(HeadsetContext);
const [open, setOpen] = React.useState(false);

const handleOpen = () => {
setOpen(true);
};

const handleClose = (device: BluetoothDevice) => {
setOpen(false);
connectDevice(device);
};

const connectDevice = (device: BluetoothDevice) => {
setHeadset(device);
};

const disconnectDevice = () => {
setHeadset(undefined);
};

return (
<Container
className={styles.BluetoothConnectionOptions}
data-testid="BluetoothConnectionOptions"
>
{!headset ? (
<Button variant="outlined" onClick={handleOpen}>
<BluetoothSearching /> Connect
</Button>
) : (
<Button variant="outlined" onClick={() => disconnectDevice()}>
<BluetoothDisabled /> Disconnect
</Button>
)}
<BluetoothConnectDialog open={open} onClose={handleClose} />
</Container>
);
};

export default BluetoothConnectionOptions;
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,24 @@ import {
ListItemText,
Typography,
} from '@mui/material';
import React, { FC, useState } from 'react';
import React, { FC, useContext, useState } from 'react';
import styles from './BluetoothDeviceSelection.module.scss';
import { Bluetooth, Refresh } from '@mui/icons-material';
import { HeadsetContext } from '../../contexts/HeadsetContext';

interface DevicesTable {
[key: string]: BluetoothDevice;
}

const BluetoothDeviceSelection: FC<{}> = () => {
interface BluetoothDeviceSelectionProps {
handleDeviceClick: (device: BluetoothDevice) => void;
}

const BluetoothDeviceSelection: FC<BluetoothDeviceSelectionProps> = (
props: BluetoothDeviceSelectionProps,
) => {
const [devices, setDevices] = useState<DevicesTable>({});
const { setHeadset } = useContext(HeadsetContext);

const refreshDevices = async () => {
const requestDeviceOptions = {
Expand All @@ -44,23 +52,18 @@ const BluetoothDeviceSelection: FC<{}> = () => {
setDevices(result);
};

const connectDevice = (device: BluetoothDevice) => {
console.log(device);
};

return (
<Container
className={styles.BluetoothDeviceSelection}
data-testid="BluetoothDeviceSelection"
>
<Typography variant="h5">Select a bluetooth device</Typography>
<Button onClick={() => refreshDevices()}>
<Refresh />
</Button>
<List>
{Object.values(devices).map((device) => (
<ListItem key={device.id}>
<ListItemButton onClick={() => connectDevice(device)}>
<ListItemButton onClick={() => props.handleDeviceClick(device)}>
<ListItemIcon>
<Bluetooth />
</ListItemIcon>
Expand Down
11 changes: 11 additions & 0 deletions client/src/components/HeadsetMonitor/HeadsetMonitor.lazy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React, { lazy, Suspense } from 'react';

const LazyHeadsetMonitor = lazy(() => import('./HeadsetMonitor'));

const HeadsetMonitor = (props: JSX.IntrinsicAttributes & { children?: React.ReactNode; }) => (
<Suspense fallback={null}>
<LazyHeadsetMonitor {...props} />
</Suspense>
);

export default HeadsetMonitor;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.HeadsetMonitor {}
12 changes: 12 additions & 0 deletions client/src/components/HeadsetMonitor/HeadsetMonitor.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/* eslint-disable */
import HeadsetMonitor from './HeadsetMonitor';

export default {
title: "HeadsetMonitor",
};

export const Default = () => <HeadsetMonitor />;

Default.story = {
name: 'default',
};
14 changes: 14 additions & 0 deletions client/src/components/HeadsetMonitor/HeadsetMonitor.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import HeadsetMonitor from './HeadsetMonitor';

describe('<HeadsetMonitor />', () => {
test('it should mount', () => {
render(<HeadsetMonitor />);

const headsetMonitor = screen.getByTestId('HeadsetMonitor');

expect(headsetMonitor).toBeInTheDocument();
});
});
14 changes: 14 additions & 0 deletions client/src/components/HeadsetMonitor/HeadsetMonitor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Container } from '@mui/material';
import React, { FC } from 'react';
import BluetoothConnectionOptions from '../BluetoothConnectionOptions/BluetoothConnectionOptions';
import styles from './HeadsetMonitor.module.scss';

const HeadsetMonitor: FC<{}> = () => {
return (
<Container className={styles.HeadsetMonitor} data-testid="HeadsetMonitor">
<BluetoothConnectionOptions />
</Container>
);
};

export default HeadsetMonitor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React, { lazy, Suspense } from 'react';

const LazyUnsupportedPlatform = lazy(() => import('./UnsupportedPlatform'));

const UnsupportedPlatform = (props: JSX.IntrinsicAttributes & { children?: React.ReactNode; }) => (
<Suspense fallback={null}>
<LazyUnsupportedPlatform {...props} />
</Suspense>
);

export default UnsupportedPlatform;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.UnsupportedPlatform {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/* eslint-disable */
import UnsupportedPlatform from './UnsupportedPlatform';

export default {
title: "UnsupportedPlatform",
};

export const Default = () => <UnsupportedPlatform />;

Default.story = {
name: 'default',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import UnsupportedPlatform from './UnsupportedPlatform';

describe('<UnsupportedPlatform />', () => {
test('it should mount', () => {
render(<UnsupportedPlatform />);

const unsupportedPlatform = screen.getByTestId('UnsupportedPlatform');

expect(unsupportedPlatform).toBeInTheDocument();
});
});
19 changes: 19 additions & 0 deletions client/src/components/UnsupportedPlatform/UnsupportedPlatform.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Container, Typography } from '@mui/material';
import React, { FC } from 'react';
import styles from './UnsupportedPlatform.module.scss';

const UnsupportedPlatform: FC<{}> = () => {
return (
<Container
className={styles.UnsupportedPlatform}
data-testid="UnsupportedPlatform"
>
<Typography textAlign="center">
Sadly, the platform you are running this application on is currently
unsupported.
</Typography>
</Container>
);
};

export default UnsupportedPlatform;

0 comments on commit 1f00bf2

Please sign in to comment.