import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import config, { SuccessOrFailType } from '../config/config'; import apiKeyInvalid from '../utils/apiKey'; import { IS_CHROME } from '../utils/operatingSystem'; import { getSettings, ProjectName, saveSettings, Settings } from '../utils/settings'; import { logUserIn } from '../utils/user'; import CustomProjectNameList from './CustomProjectNameList'; import SitesList from './SitesList'; interface State extends Settings { alertText: string; alertType: SuccessOrFailType; loading: boolean; } export default function Options(): JSX.Element { const [state, setState] = useState({ alertText: config.alert.success.text, alertType: config.alert.success.type, allowList: [], apiKey: '', apiUrl: config.apiUrl, customProjectNames: [], denyList: [], extensionStatus: 'allGood', hostname: '', loading: false, loggingEnabled: true, loggingStyle: config.loggingStyle, loggingType: config.loggingType, socialMediaSites: config.socialMediaSites, theme: config.theme, trackSocialMedia: config.trackSocialMedia, }); const isApiKeyValid = useMemo(() => apiKeyInvalid(state.apiKey) === '', [state.apiKey]); const loggingStyleRef = useRef(null); const restoreSettings = useCallback(async () => { const settings = await getSettings(); setState((oldState) => ({ ...oldState, ...settings, })); }, []); useEffect(() => { void restoreSettings(); }, [restoreSettings]); const handleSubmit = async () => { if (state.loading) return; setState((oldState) => ({ ...oldState, loading: true })); if (state.apiUrl.endsWith('/')) { state.apiUrl = state.apiUrl.slice(0, -1); } await saveSettings({ allowList: state.allowList.filter((item) => !!item.trim()), apiKey: state.apiKey, apiUrl: state.apiUrl, customProjectNames: state.customProjectNames.filter( (item) => !!item.url.trim() && !!item.projectName.trim(), ), denyList: state.denyList.filter((item) => !!item.trim()), extensionStatus: state.extensionStatus, hostname: state.hostname, loggingEnabled: state.loggingEnabled, loggingStyle: state.loggingStyle, loggingType: state.loggingType, socialMediaSites: state.socialMediaSites.filter((item) => !!item.trim()), theme: state.theme, trackSocialMedia: state.trackSocialMedia, }); setState(state); await logUserIn(state.apiKey); if (IS_CHROME) { window.close(); } }; const updateDenyListState = useCallback((denyList: string[]) => { setState((oldState) => ({ ...oldState, denyList, })); }, []); const updateAllowListState = useCallback((allowList: string[]) => { setState((oldState) => ({ ...oldState, allowList, })); }, []); const updateCustomProjectNamesState = useCallback((customProjectNames: ProjectName[]) => { setState((oldState) => ({ ...oldState, customProjectNames, })); }, []); const updateLoggingStyle = useCallback((style: string) => { setState((oldState) => ({ ...oldState, loggingStyle: style === 'allow' ? 'allow' : 'deny', })); }, []); const updateLoggingType = useCallback((type: string) => { setState((oldState) => ({ ...oldState, loggingType: type === 'url' ? 'url' : 'domain', })); }, []); const updateTheme = useCallback((theme: string) => { setState((oldState) => ({ ...oldState, theme: theme === 'light' ? 'light' : 'dark', })); }, []); const toggleSocialMedia = useCallback(() => { setState((oldState) => ({ ...oldState, trackSocialMedia: !oldState.trackSocialMedia, })); }, []); const loggingStyle = useCallback(() => { // TODO: rewrite SitesList to be structured inputs instead of textarea if (state.loggingStyle == 'deny') { return ( ); } return ( ); }, [ state.allowList, state.denyList, state.loggingStyle, updateAllowListState, updateDenyListState, ]); return (
setState({ ...state, apiKey: e.target.value })} />
{loggingStyle()}
setState({ ...state, hostname: e.target.value })} /> Optional name of local machine. By default 'Unknown Hostname'.
setState({ ...state, apiUrl: e.target.value })} placeholder="https://api.wakatime.com/api/v1" /> https://api.wakatime.com/api/v1
Track social media sites
); }