Persist authentication, make integration editor look good

pull/34/head
Sander Vocke 5 years ago
parent b4e4ac0162
commit 8111633a02
  1. 72
      client/src/components/windows/settings/IntegrationSettingsEditor.tsx
  2. 33
      client/src/lib/useAuth.tsx

@ -1,6 +1,6 @@
import React, { useState, useEffect, useCallback } from 'react';
import { useAuth } from '../../../lib/useAuth';
import { Box, CircularProgress, IconButton, Typography, FormControl, Select, MenuItem, TextField, Menu, Button } from '@material-ui/core';
import { Box, CircularProgress, IconButton, Typography, FormControl, Select, MenuItem, TextField, Menu, Button, Card, CardHeader, CardContent, CardActions } from '@material-ui/core';
import { getIntegrations, createIntegration, modifyIntegration, deleteIntegration } from '../../../lib/backend/integrations';
import AddIcon from '@material-ui/icons/Add';
import EditIcon from '@material-ui/icons/Edit';
@ -31,57 +31,61 @@ function EditSpotifyClientCredentialsDetails(props: {
onChangeClientSecret: (v: string) => void,
}) {
return <Box>
<Box display="flex" alignItems="center">
<Typography>Client id:</Typography>
{props.editing ?
<Box mt={1} mb={1}>
<TextField
variant="outlined"
disabled={!props.editing}
value={props.clientId || ""}
label="Client Id:"
fullWidth
onChange={(e: any) => props.onChangeClientId(e.target.value)}
/> :
<Typography>{props.clientId}</Typography>}
/>
</Box>
<Box display="flex" alignItems="center">
<Typography>Client secret:</Typography>
{props.editing ?
<Box mt={1} mb={1}>
<TextField
variant="outlined"
disabled={!props.editing}
value={props.clientSecret || ""}
label="Client secret:"
fullWidth
onChange={(e: any) => props.onChangeClientSecret(e.target.value)}
/> :
<Typography>{props.clientSecret}</Typography>}
/>
</Box>
</Box>;
}
function EditIntegration(props: EditIntegrationProps) {
let IntegrationHeaders: Record<any, any> = {
[serverApi.IntegrationType.SpotifyClientCredentials]: <Box display="flex" alignItems="center">
<StoreLinkIcon
[serverApi.IntegrationType.SpotifyClientCredentials]:
<Box display="flex" alignItems="center">
<Box mr={1}><StoreLinkIcon
style={{ height: '40px', width: '40px' }}
whichStore={ExternalStore.Spotify}
/>
/></Box>
<Typography>Spotify</Typography>
</Box>
}
return <Box display="flex" flexDirection="column" border={1}>
{IntegrationHeaders[props.integration.type]}
<Box display="flex" alignItems="center">
<Typography>Name:</Typography>
{props.editing ?
return <Card variant="outlined">
<CardHeader
avatar={
IntegrationHeaders[props.integration.type]
}
>
</CardHeader>
<CardContent>
<Box mt={1} mb={1}>
<TextField
variant="outlined"
value={props.integration.name || ""}
label="Name"
fullWidth
disabled={!props.editing}
onChange={(e: any) => props.onChange({
...props.integration,
name: e.target.value,
}, props.editing)}
/> :
<Typography>{props.integration.name}</Typography>}
/>
</Box>
{props.integration.type === serverApi.IntegrationType.SpotifyClientCredentials &&
<EditSpotifyClientCredentialsDetails
@ -104,6 +108,8 @@ function EditIntegration(props: EditIntegrationProps) {
}, props.editing)}
/>
}
</CardContent>
<CardActions>
{!props.editing && !props.submitting && <IconButton
onClick={() => { props.onChange(props.integration, true); }}
><EditIcon /></IconButton>}
@ -117,7 +123,8 @@ function EditIntegration(props: EditIntegrationProps) {
onClick={() => testSpotify(props.upstreamId || 0)}
>Test</Button>}
{props.submitting && <CircularProgress />}
</Box >
</CardActions>
</Card>
}
function AddIntegrationMenu(props: {
@ -198,10 +205,11 @@ export default function IntegrationSettingsEditor(props: {}) {
}
const deleteEditor = (state: EditorState) => {
if (!state.upstreamId) {
throw new Error('Cannot delete integration: has no upstream')
}
deleteIntegration(state.upstreamId).then((response: any) => {
let promise: Promise<void> = state.upstreamId ?
deleteIntegration(state.upstreamId) :
(async () => {})();
promise.then((response: any) => {
let cpy = _.cloneDeep(editors).filter(
(e: any) => e.id !== state.id
);
@ -225,13 +233,12 @@ export default function IntegrationSettingsEditor(props: {}) {
});
}, []);
// FIXME: add button should show a drop-down to choose a fixed integration type.
// Otherwise we need dynamic switching of the type's fields.
return <>
<Box>
{editors === null && <CircularProgress />}
{editors && <>
{editors.map((state: EditorState) => <EditIntegration
{editors && <Box display="flex" flexDirection="column" alignItems="center" flexWrap="wrap">
{editors.map((state: EditorState) => <Box m={1} width="90%">
<EditIntegration
upstreamId={state.upstreamId}
integration={state.integration}
original={state.original}
@ -276,11 +283,12 @@ export default function IntegrationSettingsEditor(props: {}) {
setEditors(cpy);
deleteEditor(state);
}}
/>)}
/>
</Box>)}
<IconButton onClick={onOpenAddMenu}>
<AddIcon />
</IconButton>
</>}
</Box>}
</Box>
<AddIntegrationMenu
position={addMenuPos}

@ -38,8 +38,37 @@ export const useAuth = () => {
return useContext(authContext);
};
function persistAuth(auth: AuthUser | null) {
let s = window.sessionStorage;
if(auth === null) {
s.removeItem('userId');
s.removeItem('userEmail');
return;
}
s.setItem('userId', auth.id.toString());
s.setItem('userEmail', auth.email);
// TODO icon
}
function loadAuth(): AuthUser | null {
let s = window.sessionStorage;
let id = s.getItem('userId');
let email = s.getItem('userEmail');
if (id && email) {
return {
id: parseInt(id),
email: email,
icon: <PersonIcon />
}
}
return null;
}
function useProvideAuth() {
const [user, setUser] = useState<AuthUser | null>(null);
const [user, setUser] = useState<AuthUser | null>(loadAuth());
// TODO: password maybe shouldn't be encoded into the URL.
const signin = (email: string, password: string) => {
@ -59,6 +88,7 @@ function useProvideAuth() {
icon: <PersonIcon />,
}
setUser(user);
persistAuth(user);
return user;
})();
};
@ -89,6 +119,7 @@ function useProvideAuth() {
throw new Error("Failed to log out.");
}
setUser(null);
persistAuth(null);
})();
};

Loading…
Cancel
Save