New top-level React root: <App />

This commit is contained in:
Josh Perez 2021-06-14 15:01:00 -04:00 committed by GitHub
parent 9a1f722545
commit 173771d34b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 457 additions and 266 deletions

42
ts/components/App.tsx Normal file
View file

@ -0,0 +1,42 @@
import React from 'react';
import classNames from 'classnames';
import { AppViewType } from '../state/ducks/app';
import { Inbox } from './Inbox';
import { Install } from './Install';
import { StandaloneRegistration } from './StandaloneRegistration';
import { ThemeType } from '../types/Util';
export type PropsType = {
appView: AppViewType;
hasInitialLoadCompleted: boolean;
theme: ThemeType;
};
export const App = ({
appView,
hasInitialLoadCompleted,
theme,
}: PropsType): JSX.Element => {
let contents;
if (appView === AppViewType.Installer) {
contents = <Install />;
} else if (appView === AppViewType.Standalone) {
contents = <StandaloneRegistration />;
} else if (appView === AppViewType.Inbox) {
contents = <Inbox hasInitialLoadCompleted={hasInitialLoadCompleted} />;
}
return (
<div
className={classNames({
App: true,
'light-theme': theme === ThemeType.light,
'dark-theme': theme === ThemeType.dark,
})}
>
{contents}
</div>
);
};

View file

@ -0,0 +1,35 @@
import React, { useEffect, useRef } from 'react';
import * as Backbone from 'backbone';
type PropsType = {
View: typeof Backbone.View;
className?: string;
};
export const BackboneHost = ({ View, className }: PropsType): JSX.Element => {
const hostRef = useRef<HTMLDivElement | null>(null);
const viewRef = useRef<Backbone.View | undefined>(undefined);
useEffect(() => {
const view = new View({
el: hostRef.current,
});
viewRef.current = view;
return () => {
if (!viewRef || !viewRef.current) {
return;
}
viewRef.current.remove();
viewRef.current = undefined;
};
}, [View]);
return (
<div>
<div className={className} ref={hostRef} />
</div>
);
};

48
ts/components/Inbox.tsx Normal file
View file

@ -0,0 +1,48 @@
import React, { useEffect, useRef } from 'react';
import * as Backbone from 'backbone';
type InboxViewType = Backbone.View & {
onEmpty?: () => void;
};
type InboxViewOptionsType = Backbone.ViewOptions & {
initialLoadComplete: boolean;
window: typeof window;
};
export type PropsType = {
hasInitialLoadCompleted: boolean;
};
export const Inbox = ({ hasInitialLoadCompleted }: PropsType): JSX.Element => {
const hostRef = useRef<HTMLDivElement | null>(null);
const viewRef = useRef<InboxViewType | undefined>(undefined);
useEffect(() => {
const viewOptions: InboxViewOptionsType = {
el: hostRef.current,
initialLoadComplete: false,
window,
};
const view = new window.Whisper.InboxView(viewOptions);
viewRef.current = view;
return () => {
if (!viewRef || !viewRef.current) {
return;
}
viewRef.current.remove();
viewRef.current = undefined;
};
}, []);
useEffect(() => {
if (hasInitialLoadCompleted && viewRef.current && viewRef.current.onEmpty) {
viewRef.current.onEmpty();
}
}, [hasInitialLoadCompleted, viewRef]);
return <div className="inbox index" ref={hostRef} />;
};

11
ts/components/Install.tsx Normal file
View file

@ -0,0 +1,11 @@
import React from 'react';
import { BackboneHost } from './BackboneHost';
export const Install = (): JSX.Element => {
return (
<BackboneHost
className="full-screen-flow"
View={window.Whisper.InstallView}
/>
);
};

View file

@ -0,0 +1,11 @@
import React from 'react';
import { BackboneHost } from './BackboneHost';
export const StandaloneRegistration = (): JSX.Element => {
return (
<BackboneHost
className="full-screen-flow"
View={window.Whisper.StandaloneRegistrationView}
/>
);
};