diff --git a/assets/js/components/Options.jsx b/assets/js/components/Options.jsx index 62a8c79..419675a 100644 --- a/assets/js/components/Options.jsx +++ b/assets/js/components/Options.jsx @@ -152,7 +152,7 @@ var Options = reactCreateClass({ handleChange={that._updateWhitelistState} label="Whitelist" sites={that.state.whitelist} - placeholder="http://google.com http://myproject.com@@MyProject" + placeholder="http://google.com http://myproject.com/MyProject" helpText="Sites that you want to show in your reports. You can assign URL to project by adding @@YourProject at the end of line." /> ); diff --git a/src/components/Options.tsx b/src/components/Options.tsx new file mode 100644 index 0000000..f85faf4 --- /dev/null +++ b/src/components/Options.tsx @@ -0,0 +1,227 @@ +import React, { useRef, useState, useEffect } from 'react'; +import config, { SuccessOrFailType } from '../config/config'; +import Alert from './Alert'; +import SitesList from './SitesList'; + +interface State { + alertText: string; + alertType: SuccessOrFailType; + blacklist: string; + displayAlert: boolean; + loading: boolean; + loggingStyle: string; + loggingType: string; + theme: string; + whitelist: string; +} +export default function Options(): JSX.Element { + const [state, setState] = useState({ + alertText: config.alert.success.text, + alertType: config.alert.success.type, + blacklist: '', + displayAlert: false, + loading: false, + loggingStyle: config.loggingStyle, + loggingType: config.loggingType, + theme: config.theme, + whitelist: '', + }); + + const loggingStyleRef = useRef(null); + + const restoreSettings = async (): Promise => { + const items = await browser.storage.sync.get({ + blacklist: '', + loggingStyle: config.loggingStyle, + loggingType: config.loggingType, + theme: config.theme, + whitelist: '', + }); + setState({ + ...state, + blacklist: items.blacklist, + loggingStyle: items.loggingStyle, + loggingType: items.loggingType, + theme: items.theme, + whitelist: items.whitelist, + }); + }; + + useEffect(() => { + void restoreSettings(); + }, []); + + useEffect(() => { + if (state.displayAlert) { + setTimeout(function () { + setState({ ...state, displayAlert: false, loading: false }); + }, 2500); + } + }, [state.displayAlert]); + + const handleSubmit = async () => { + if (state.loading) return; + setState({ ...state, loading: true }); + + const theme = state.theme; + const loggingType = state.loggingType; + const loggingStyle = state.loggingStyle; + // Trimming blacklist and whitelist removes blank lines and spaces. + const blacklist = state.blacklist.trim(); + const whitelist = state.whitelist.trim(); + + // Sync options with google storage. + await browser.storage.sync.set({ + blacklist: blacklist, + loggingStyle: loggingStyle, + loggingType: loggingType, + theme: theme, + whitelist: whitelist, + }); + + // Set state to be newly entered values. + setState({ + ...state, + blacklist: blacklist, + displayAlert: true, + loggingStyle: loggingStyle, + loggingType: loggingType, + theme: theme, + whitelist: whitelist, + }); + }; + + const updateBlacklistState = (sites: string) => { + setState({ + ...state, + blacklist: sites, + }); + }; + + const updateWhitelistState = (sites: string) => { + setState({ + ...state, + whitelist: sites, + }); + }; + + const loggingStyle = function () { + if (state.loggingStyle == 'blacklist') { + return ( + + ); + } + + return ( + + ); + }; + + const alert = () => { + return ( +
+ +
+ ); + }; + + return ( +
+
+
+ {alert()} + +
+
+ + +
+ +
+
+ + {loggingStyle()} + +
+ + +
+ +
+
+ +
+ + +
+ +
+
+ +
+
+ +
+
+
+
+
+
+ ); +} diff --git a/src/components/SitesList.tsx b/src/components/SitesList.tsx new file mode 100644 index 0000000..da9fe5f --- /dev/null +++ b/src/components/SitesList.tsx @@ -0,0 +1,44 @@ +import React from 'react'; + +type Props = { + handleChange: (sites: string) => void; + helpText: string; + label: string; + placeholder?: string; + sites: string; +}; + +export default function SitesList({ + handleChange, + label, + placeholder, + sites, + helpText, +}: Props): JSX.Element { + const textareaChange = (event: React.ChangeEvent) => { + handleChange(event.target.value); + }; + + return ( +
+ + +
+ + + {helpText} +
+ One line per site. +
+
+
+ ); +} diff --git a/src/options.tsx b/src/options.tsx index 6bc1dae..ab0582d 100644 --- a/src/options.tsx +++ b/src/options.tsx @@ -1,6 +1,12 @@ import React from 'react'; -import ReactDOM from 'react-dom'; +import { createRoot } from 'react-dom/client'; +import Options from './components/Options'; + +/* This is a fix for Bootstrap requiring jQuery */ +global.jQuery = require('jquery'); +require('bootstrap'); const container = document.getElementById('wakatime-options'); +const root = createRoot(container!); -ReactDOM.render(

OPTIONS GO HERE

, container); +root.render();