Jeremy Kahn ea34058fa7
chore: Migrate from Create React App to Vite (#231)
* chore(vite): use vite

* fix(vite): alias lib directory

* chore(vite): set type: module

* chore: update vite and MUI

* fix(vite): make MUI components load

* fix: use node path resolution

* chore(vite): add svg support

* fix(vite): polyfill global

* fix(vite): use import.meta

* fix(vite): use correct svg module resolution

* chore(vite): migrate to vitest

* fix(vite): remove PUBLIC_URL

* fix(tests): mock audio service

* chore(deps): upgrade to react test library 14

* refactor(tests): simplify room test setup

* refactor(tests): make Date.now() mockable

* refactor(vite): remove bootstrap shim

* chore(deps): drop react-scripts

* chore(deps): remove source-map-explorer

Source maps do not currently work with MUI and Vite:
https://github.com/vitejs/vite/issues/15012

Because of this, source map utilities are currently removed.

* refactor(vite): use TypeScript for Vite config

* chore(actions): update actions config for new paths

* fix(service-worker): use VITE_HOMEPAGE for service worker resolution

* fix(vercel): use quotes for build command

* fix(vite): use import.meta.env.MODE

* fix(service-worker): use correct definition for publicUrl

* feat(vite): use vite-plugin-pwa

* fix(pwa): make update prompt work

* fix(types): use vite/client types

* docs(readme): update building instructions

* refactor(vite): simplify theme loading workaround

* refactor(vite): use manifest object

* docs(readme): update tool references

* chore(deps): run `npm audit fix`

* fix(vite): make syntax highlighter work consistently

See: https://github.com/react-syntax-highlighter/react-syntax-highlighter/issues/513

* fix(pwa): remove manifest.json references

* refactor(deps): remove jest references

* refactor(types): remove react-scripts reference

* chore(deps): use TypeScript 5

* refactor(tests): improve persisted storage mocking
2024-03-12 21:44:43 -05:00

199 lines
5.7 KiB
TypeScript

import React, { useEffect, useContext, useState } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import Button from '@mui/material/Button'
import Box from '@mui/material/Box'
import FormControl from '@mui/material/FormControl'
import Typography from '@mui/material/Typography'
import TextField from '@mui/material/TextField'
import Divider from '@mui/material/Divider'
import IconButton from '@mui/material/IconButton'
import MuiLink from '@mui/material/Link'
import GitHubIcon from '@mui/icons-material/GitHub'
import Cached from '@mui/icons-material/Cached'
import { v4 as uuid } from 'uuid'
import { routes } from 'config/routes'
import { ShellContext } from 'contexts/ShellContext'
import { PeerNameDisplay } from 'components/PeerNameDisplay'
import Logo from 'img/logo.svg?react'
import { EmbedCodeDialog } from './EmbedCodeDialog'
interface HomeProps {
userId: string
}
export function Home({ userId }: HomeProps) {
const { setTitle } = useContext(ShellContext)
const [roomName, setRoomName] = useState(uuid())
const [showEmbedCode, setShowEmbedCode] = useState(false)
const navigate = useNavigate()
useEffect(() => {
setTitle('Chitchatter')
}, [setTitle])
const handleRoomNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const { value } = event.target
setRoomName(value)
}
const handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
event.preventDefault()
}
const handleJoinPublicRoomClick = () => {
navigate(`/public/${roomName}`)
}
const handleJoinPrivateRoomClick = () => {
navigate(`/private/${roomName}`)
}
const handleGetEmbedCodeClick = () => {
setShowEmbedCode(true)
}
const handleEmbedCodeWindowClose = () => {
setShowEmbedCode(false)
}
const isRoomNameValid = roomName.length > 0
return (
<Box className="Home">
<main className="mt-6 px-4 max-w-3xl text-center mx-auto">
<Link to={routes.ABOUT}>
<Logo className="px-1 pb-4 mx-auto max-w-md" />
</Link>
<form onSubmit={handleFormSubmit} className="max-w-xl mx-auto">
<Typography sx={{ mb: 2 }}>
Your username:{' '}
<PeerNameDisplay paragraph={false} sx={{ fontWeight: 'bold' }}>
{userId}
</PeerNameDisplay>
</Typography>
<FormControl fullWidth>
<TextField
label="Room name (generated client-side)"
variant="outlined"
value={roomName}
onChange={handleRoomNameChange}
InputProps={{
endAdornment: (
<IconButton
aria-label="Regenerate room id"
onClick={() => setRoomName(uuid())}
size="small"
>
<Cached />
</IconButton>
),
sx: { fontSize: { xs: '0.9rem', sm: '1rem' } },
}}
size="medium"
/>
</FormControl>
<Box
sx={{
display: 'flex',
justifyContent: 'center',
}}
>
<Button
variant="contained"
onClick={handleJoinPublicRoomClick}
sx={{
marginTop: 2,
}}
disabled={!isRoomNameValid}
>
Join public room
</Button>
<Button
variant="contained"
onClick={handleJoinPrivateRoomClick}
sx={{
marginTop: 2,
marginLeft: 2,
}}
disabled={!isRoomNameValid}
>
Join private room
</Button>
<Button
variant="contained"
color="secondary"
onClick={handleGetEmbedCodeClick}
sx={{
marginTop: 2,
marginLeft: 2,
}}
disabled={!isRoomNameValid}
>
Get embed code
</Button>
</Box>
</form>
</main>
<Divider sx={{ my: 2 }} />
<Box className="max-w-3xl text-center mx-auto px-4">
<Typography variant="body1">
This is a free communication tool that is designed for simplicity,
privacy, and security. All interaction between you and your online
peers is encrypted. There is no record of your conversation once you
all leave.
</Typography>
</Box>
<Box
sx={{
mx: 'auto',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<MuiLink
href="https://github.com/jeremyckahn/chitchatter"
target="_blank"
sx={theme => ({
color: theme.palette.text.primary,
})}
>
<IconButton
size="large"
edge="start"
color="inherit"
aria-label="Open menu"
>
<GitHubIcon sx={{ fontSize: '2em' }} />
</IconButton>
</MuiLink>
</Box>
<Typography variant="body1" sx={{ textAlign: 'center' }}>
Licensed under{' '}
<MuiLink
href="https://github.com/jeremyckahn/chitchatter/blob/develop/LICENSE"
target="_blank"
>
GPL v2
</MuiLink>
. Please{' '}
<MuiLink
href="https://github.com/jeremyckahn/chitchatter/blob/develop/README.md"
target="_blank"
>
read the docs
</MuiLink>
.
</Typography>
<EmbedCodeDialog
showEmbedCode={showEmbedCode}
handleEmbedCodeWindowClose={handleEmbedCodeWindowClose}
roomName={roomName}
/>
</Box>
)
}