Merge pull request #159 from wakatime/sebas-move-api-key-input-to-options

chore: move api key input to options view
This commit is contained in:
Juan Sebastian velez Posada
2023-01-19 08:30:06 -05:00
committed by GitHub
5 changed files with 77 additions and 84 deletions

View File

@@ -28,3 +28,11 @@ canvas#icon {
div#status { div#status {
display: none; display: none;
} }
[type='text'].border-danger,
.border-danger {
box-shadow: inset 0 -2px 0 @brand-danger;
&:focus {
.box-shadow(inset 0 -2px 0 @brand-danger);
}
}

View File

@@ -1,32 +1,13 @@
import React, { useEffect, useState } from 'react'; import React from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { configLogout, setApiKey } from '../reducers/configReducer'; import { ReduxSelector } from '../types/store';
import { userLogout } from '../reducers/currentUser';
import { ApiKeyReducer, ReduxSelector } from '../types/store';
import { User } from '../types/user'; import { User } from '../types/user';
import apiKeyInvalid from '../utils/apiKey';
import { fetchUserData } from '../utils/user';
export default function NavBar(): JSX.Element { export default function NavBar(): JSX.Element {
const [state, setState] = useState({
apiKey: '',
apiKeyError: '',
loading: false,
});
const dispatch = useDispatch();
const { apiKey: apiKeyFromRedux }: ApiKeyReducer = useSelector(
(selector: ReduxSelector) => selector.config,
);
const user: User | undefined = useSelector( const user: User | undefined = useSelector(
(selector: ReduxSelector) => selector.currentUser.user, (selector: ReduxSelector) => selector.currentUser.user,
); );
useEffect(() => {
setState({ ...state, apiKey: apiKeyFromRedux });
}, [apiKeyFromRedux]);
const signedInAs = () => { const signedInAs = () => {
if (user) { if (user) {
return ( return (
@@ -127,50 +108,6 @@ export default function NavBar(): JSX.Element {
</li> </li>
</ul> </ul>
</li> </li>
<li>
<div className="container-fluid">
{state.apiKeyError && (
<div className="alert alert-danger" role="alert">
{state.apiKeyError}
</div>
)}
<div className="input-group">
<input
type="text"
className="form-control"
placeholder="API key"
value={state.apiKey}
onChange={(e) => {
const key = e.target.value;
const isApiKeyInvalid = apiKeyInvalid(key);
setState({ ...state, apiKey: key, apiKeyError: isApiKeyInvalid });
}}
/>
<span className="input-group-btn">
<button
className={`btn btn-default ${state.loading ? 'disabled' : ''}`}
disabled={state.loading}
type="button"
data-loading-text="Loading..."
onClick={async () => {
if (state.apiKeyError === '' && state.apiKey !== '') {
setState({ ...state, loading: true });
await browser.storage.sync.set({ apiKey: state.apiKey });
dispatch(configLogout());
dispatch(userLogout());
dispatch(setApiKey(state.apiKey));
await fetchUserData(state.apiKey, dispatch);
setState({ ...state, loading: false });
}
}}
>
Save
</button>
</span>
</div>
</div>
</li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@@ -1,11 +1,14 @@
import React, { useRef, useState, useEffect } from 'react'; import React, { useRef, useState, useEffect } from 'react';
import config, { SuccessOrFailType } from '../config/config'; import config, { SuccessOrFailType } from '../config/config';
import apiKeyInvalid from '../utils/apiKey';
import { logUserIn } from '../utils/user';
import Alert from './Alert'; import Alert from './Alert';
import SitesList from './SitesList'; import SitesList from './SitesList';
interface State { interface State {
alertText: string; alertText: string;
alertType: SuccessOrFailType; alertType: SuccessOrFailType;
apiKey: string;
blacklist: string; blacklist: string;
displayAlert: boolean; displayAlert: boolean;
loading: boolean; loading: boolean;
@@ -18,6 +21,7 @@ export default function Options(): JSX.Element {
const [state, setState] = useState<State>({ const [state, setState] = useState<State>({
alertText: config.alert.success.text, alertText: config.alert.success.text,
alertType: config.alert.success.type, alertType: config.alert.success.type,
apiKey: '',
blacklist: '', blacklist: '',
displayAlert: false, displayAlert: false,
loading: false, loading: false,
@@ -31,6 +35,7 @@ export default function Options(): JSX.Element {
const restoreSettings = async (): Promise<void> => { const restoreSettings = async (): Promise<void> => {
const items = await browser.storage.sync.get({ const items = await browser.storage.sync.get({
apiKey: config.apiKey,
blacklist: '', blacklist: '',
loggingStyle: config.loggingStyle, loggingStyle: config.loggingStyle,
loggingType: config.loggingType, loggingType: config.loggingType,
@@ -39,11 +44,12 @@ export default function Options(): JSX.Element {
}); });
setState({ setState({
...state, ...state,
blacklist: items.blacklist, apiKey: items.apiKey as string,
loggingStyle: items.loggingStyle, blacklist: items.blacklist as string,
loggingType: items.loggingType, loggingStyle: items.loggingStyle as string,
theme: items.theme, loggingType: items.loggingType as string,
whitelist: items.whitelist, theme: items.theme as string,
whitelist: items.whitelist as string,
}); });
}; };
@@ -63,6 +69,7 @@ export default function Options(): JSX.Element {
if (state.loading) return; if (state.loading) return;
setState({ ...state, loading: true }); setState({ ...state, loading: true });
const apiKey = state.apiKey;
const theme = state.theme; const theme = state.theme;
const loggingType = state.loggingType; const loggingType = state.loggingType;
const loggingStyle = state.loggingStyle; const loggingStyle = state.loggingStyle;
@@ -72,23 +79,26 @@ export default function Options(): JSX.Element {
// Sync options with google storage. // Sync options with google storage.
await browser.storage.sync.set({ await browser.storage.sync.set({
blacklist: blacklist, apiKey,
loggingStyle: loggingStyle, blacklist,
loggingType: loggingType, loggingStyle,
theme: theme, loggingType,
whitelist: whitelist, theme,
whitelist,
}); });
// Set state to be newly entered values. // Set state to be newly entered values.
setState({ setState({
...state, ...state,
blacklist: blacklist, apiKey,
blacklist,
displayAlert: true, displayAlert: true,
loggingStyle: loggingStyle, loggingStyle,
loggingType: loggingType, loggingType,
theme: theme, theme,
whitelist: whitelist, whitelist,
}); });
await logUserIn(state.apiKey);
}; };
const updateBlacklistState = (sites: string) => { const updateBlacklistState = (sites: string) => {
@@ -142,11 +152,14 @@ export default function Options(): JSX.Element {
); );
}; };
const isApiKeyValid = apiKeyInvalid(state.apiKey) === '';
return ( return (
<div <div
className="container" className="container"
style={{ style={{
height: 515, height: 590,
marginTop: 0,
overflow: 'hidden', overflow: 'hidden',
overflowY: 'scroll', overflowY: 'scroll',
}} }}
@@ -156,6 +169,21 @@ export default function Options(): JSX.Element {
{alert()} {alert()}
<form className="form-horizontal"> <form className="form-horizontal">
<div className="form-group">
<label className="col-lg-2 control-label">API Key</label>
<div className="col-lg-10">
<input
autoFocus={true}
type="text"
className={`form-control ${isApiKeyValid ? '' : 'border-danger'}`}
placeholder="API key"
value={state.apiKey}
onChange={(e) => setState({ ...state, apiKey: e.target.value })}
/>
</div>
</div>
<div className="form-group"> <div className="form-group">
<label className="col-lg-2 control-label">Logging style!</label> <label className="col-lg-2 control-label">Logging style!</label>

View File

@@ -15,7 +15,7 @@ export default function WakaTime(): JSX.Element {
}: ApiKeyReducer = useSelector((selector: ReduxSelector) => selector.config); }: ApiKeyReducer = useSelector((selector: ReduxSelector) => selector.config);
useEffect(() => { useEffect(() => {
fetchUserData(apiKeyFromRedux, dispatch); void fetchUserData(apiKeyFromRedux, dispatch);
}, []); }, []);
return ( return (

View File

@@ -5,6 +5,26 @@ import WakaTimeCore from '../core/WakaTimeCore';
import { setUser } from '../reducers/currentUser'; import { setUser } from '../reducers/currentUser';
import changeExtensionState from './changeExtensionState'; import changeExtensionState from './changeExtensionState';
export const logUserIn = async (apiKey: string): Promise<void> => {
if (!apiKey) {
await changeExtensionState('notSignedIn');
return;
}
try {
await WakaTimeCore.checkAuth(apiKey);
const items = await browser.storage.sync.get({ loggingEnabled: config.loggingEnabled });
if (items.loggingEnabled === true) {
await changeExtensionState('allGood');
} else {
await changeExtensionState('notLogging');
}
} catch (err: unknown) {
await changeExtensionState('notSignedIn');
}
};
export const fetchUserData = async ( export const fetchUserData = async (
apiKey: string, apiKey: string,
dispatch: Dispatch<AnyAction>, dispatch: Dispatch<AnyAction>,
@@ -18,7 +38,7 @@ export const fetchUserData = async (
} }
if (!apiKey) { if (!apiKey) {
await changeExtensionState('notSignedIn'); return changeExtensionState('notSignedIn');
} }
try { try {