-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make Transcripts page Responsive. (#93)
Hugely clean up some of the component names, provider structures, pass the MUI sx property through, fix up theme palette to be more standard, and handle some "empty entry" problems in the database causing errors. Lastly, migrate to Firebase App Hosting instead of Webframeworks. Sadly this removes the ability to do PR instances for now. We mitigate by adding a staging branch and kickin' it oldskool.
- Loading branch information
Showing
33 changed files
with
1,151 additions
and
645 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export type ApiResponse = { | ||
ok: boolean; | ||
message: string; | ||
data: any; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
'use client' | ||
|
||
import ActionDialogConstants from 'components/ActionDialogConstants'; | ||
import Dialog from '@mui/material/Dialog'; | ||
import SpeakerEditDialogContent from 'components/SpeakerEditDialogContent'; | ||
import UploadChangesDialogContent from 'components/UploadChangesDialogContent'; | ||
import { useActionDialog } from 'components/ActionDialogProvider'; | ||
|
||
function makeContents(actionDialogMode, handleClose) { | ||
if (actionDialogMode?.mode === ActionDialogConstants.speakerMode) { | ||
return ( | ||
<SpeakerEditDialogContent | ||
speakerNum={actionDialogMode.params.speakerNum} | ||
onClose={handleClose}/> | ||
); | ||
} else if (actionDialogMode?.mode === ActionDialogConstants.uploadChangesMode) { | ||
return (<UploadChangesDialogContent onClose={handleClose}/>); | ||
} | ||
|
||
return (<></>); | ||
} | ||
|
||
export default function ActionDialog() { | ||
const {actionDialogMode, setActionDialogMode} = useActionDialog(); | ||
|
||
const handleClose = (value: string) => { | ||
setActionDialogMode(undefined); // Dismisses Dialog. | ||
}; | ||
|
||
return ( | ||
<Dialog onClose={handleClose} open={actionDialogMode !== undefined}> | ||
{makeContents(actionDialogMode, handleClose)} | ||
</Dialog> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
const actionDialogModes = { | ||
uploadChangesMode: "upload_changes", | ||
speakerMode: "speakerMode", | ||
}; | ||
|
||
export default actionDialogModes; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import CloseIcon from '@mui/icons-material/Close'; | ||
import DialogContent from '@mui/material/DialogContent'; | ||
import DialogTitle from '@mui/material/DialogTitle'; | ||
import IconButton from '@mui/material/IconButton'; | ||
import Stack from '@mui/material/Stack'; | ||
|
||
type ActionDialogContentsParams = { | ||
title: string; | ||
children: React.ReactNode; | ||
onClose: (value: string) => void; | ||
}; | ||
|
||
export default function ActionDialogContents({title, children, onClose}) { | ||
return ( | ||
<> | ||
<DialogTitle> | ||
<Stack | ||
direction="row" | ||
sx={{ | ||
justifyContent:"space-between", | ||
alignItems:"center"}}> | ||
{title} | ||
<IconButton onClick={onClose}> | ||
<CloseIcon fontSize="inherit"/> | ||
</IconButton> | ||
</Stack> | ||
</DialogTitle> | ||
<DialogContent> | ||
{children} | ||
</DialogContent> | ||
</> | ||
); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
'use client' | ||
|
||
import { createContext, useContext, useState, useMemo } from 'react'; | ||
|
||
type ActionDialogMode = { | ||
mode: string; | ||
params?: string | number; | ||
}; | ||
|
||
type ActionDialogModeType = { | ||
actionDialogMode : ActionDialogMode | undefined; | ||
setActionDialogMode: (x: ActionDialogMode | undefined) => void; | ||
}; | ||
|
||
type DialogProviderParams = { | ||
children: React.ReactNode; | ||
}; | ||
|
||
// Pattern from https://stackoverflow.com/a/74174425 | ||
const ActionDialogModeContext = createContext<ActionDialogModeType | undefined>(undefined); | ||
|
||
export function useActionDialog() { | ||
const context = useContext(ActionDialogModeContext); | ||
if (context === undefined) { | ||
throw new Error('Missing <ActionDialogModeProvider>') | ||
} | ||
|
||
return context; | ||
} | ||
|
||
export default function ActionDialogModeProvider({children}: DialogProviderParams) { | ||
const [actionDialogMode, setActionDialogMode] = useState<ActionDialogMode | undefined>(undefined); | ||
|
||
const value = useMemo(() => ({ actionDialogMode, setActionDialogMode }), [actionDialogMode]); | ||
|
||
return ( | ||
<ActionDialogModeContext.Provider value={value}> | ||
{useMemo(() => ( | ||
<> | ||
{children} | ||
</> | ||
), [children])} | ||
</ActionDialogModeContext.Provider> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
'use client' | ||
|
||
import { createContext, useContext, useState, useMemo } from 'react' | ||
import { isEqual, cloneDeep } from 'lodash-es' | ||
|
||
import type { CategoryId, VideoId } from 'common/params'; | ||
import type { ExistingNames, TagSet, SpeakerInfoData } from 'utilities/client/speaker' | ||
|
||
type LastPublishedState = { | ||
speakerInfo: SpeakerInfoData; | ||
}; | ||
|
||
type AnnotationsContextParams = { | ||
children: React.ReactNode; | ||
category: CategoryId; | ||
videoId: VideoId; | ||
initialSpeakerInfo: SpeakerInfoData; | ||
initialExistingNames: ExistingNames; | ||
initialExistingTags: TagSet; | ||
}; | ||
|
||
class AnnotationsContextState { | ||
readonly category: CategoryId; | ||
readonly videoId: VideoId; | ||
|
||
readonly speakerInfo: SpeakerInfoData; | ||
readonly setSpeakerInfo:(x: SpeakerInfoData) => void; | ||
|
||
readonly existingNames: ExistingNames; | ||
readonly setExistingNames: (x: ExistingNames) => void; | ||
|
||
readonly existingTags: TagSet; | ||
readonly setExistingTags: (x: TagSet) => void; | ||
|
||
readonly lastPublishedState: LastPublishedState; | ||
readonly setLastPublishedState: (x: LastPublishedState) => void; | ||
|
||
constructor( | ||
category: CategoryId, | ||
videoId: VideoId, | ||
|
||
speakerInfo: SpeakerInfoData, | ||
setSpeakerInfo:(x: SpeakerInfoData) => void, | ||
|
||
existingNames: ExistingNames, | ||
setExistingNames: (x: ExistingNames) => void, | ||
|
||
existingTags: TagSet, | ||
setExistingTags: (x: TagSet) => void, | ||
|
||
lastPublishedState: LastPublishedState, | ||
setLastPublishedState: (x: LastPublishedState) => void) { | ||
this.category = category; | ||
this.videoId = videoId; | ||
|
||
this.speakerInfo = speakerInfo; | ||
this.setSpeakerInfo = setSpeakerInfo; | ||
|
||
this.existingNames = existingNames; | ||
this.setExistingNames = setExistingNames; | ||
|
||
this.existingTags = existingTags; | ||
this.setExistingTags = setExistingTags; | ||
|
||
this.lastPublishedState = lastPublishedState; | ||
this.setLastPublishedState = setLastPublishedState; | ||
} | ||
|
||
needsPublish() : boolean { | ||
return !isEqual(this.lastPublishedState?.speakerInfo, this?.speakerInfo); | ||
} | ||
} | ||
|
||
// Pattern from https://stackoverflow.com/a/74174425 | ||
const AnnotationsContext = | ||
createContext<AnnotationsContextState | undefined>(undefined); | ||
|
||
// Pattern from https://kentcdodds.com/blog/how-to-use-react-context-effectively | ||
export function useAnnotations() { | ||
const context = useContext(AnnotationsContext); | ||
if (context === undefined) { | ||
throw new Error('Missing <AnnotationsProvider>') | ||
} | ||
|
||
return context; | ||
} | ||
|
||
export default function AnnotationsProvider({ | ||
children, category, videoId, initialSpeakerInfo, initialExistingNames, initialExistingTags}: AnnotationsContextParams) { | ||
|
||
const [speakerInfo, setSpeakerInfo] = useState<SpeakerInfoData>(initialSpeakerInfo) | ||
const [existingNames, setExistingNames] = useState<ExistingNames>(initialExistingNames); | ||
const [existingTags, setExistingTags] = useState<TagSet>(initialExistingTags); | ||
|
||
const [lastPublishedState, setLastPublishedState] = useState<LastPublishedState>( | ||
{ | ||
speakerInfo: cloneDeep(initialSpeakerInfo), | ||
} | ||
); | ||
|
||
const value = useMemo(() => (new AnnotationsContextState( | ||
category, | ||
videoId, | ||
speakerInfo, | ||
setSpeakerInfo, | ||
existingNames, | ||
setExistingNames, | ||
existingTags, | ||
setExistingTags, | ||
lastPublishedState, | ||
setLastPublishedState, | ||
)), | ||
[speakerInfo, existingNames, existingTags, lastPublishedState, category, videoId] | ||
); | ||
|
||
return ( | ||
<AnnotationsContext.Provider value={value}> | ||
{useMemo(() => ( | ||
<> | ||
{children} | ||
</> | ||
), [children])} | ||
</AnnotationsContext.Provider> | ||
) | ||
} |
Oops, something went wrong.