mirror of
https://github.com/thedevs-network/kutt-extension.git
synced 2026-02-03 13:53:23 +00:00
fix: get hostUrl from form submission values itself in options page
This commit is contained in:
@@ -7,7 +7,11 @@ import { browser } from 'webextension-polyfill-ts';
|
||||
|
||||
import axios, { AxiosPromise } from 'axios';
|
||||
import * as constants from './constants';
|
||||
import { Kutt } from '../Popup/Popup';
|
||||
|
||||
export enum Kutt {
|
||||
hostDomain = 'kutt.it',
|
||||
hostUrl = 'https://kutt.it',
|
||||
}
|
||||
|
||||
type ShortenUrlBodyProperties = {
|
||||
target: string;
|
||||
@@ -43,7 +47,7 @@ export type SuccessfulShortenStatusProperties = {
|
||||
data: ShortenLinkResponseProperties;
|
||||
};
|
||||
|
||||
type HostUrlProperties = typeof Kutt.hostUrl;
|
||||
type HostUrlProperties = string;
|
||||
|
||||
export type DomainEntryProperties = {
|
||||
address: string;
|
||||
|
||||
@@ -2,12 +2,21 @@ import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { getExtensionSettings } from '../util/settings';
|
||||
import BodyWrapper from '../components/BodyWrapper';
|
||||
import { isValidUrl } from '../util/tabs';
|
||||
import Loader from '../components/Loader';
|
||||
import OptionsForm, { OptionsFormValuesProperties } from './OptionsForm';
|
||||
import OptionsForm from './OptionsForm';
|
||||
|
||||
export type ExtensionConfigProperties = {
|
||||
apikey: string;
|
||||
autocopy: boolean;
|
||||
history: boolean;
|
||||
advanced: boolean;
|
||||
customhost: string; // for form values
|
||||
};
|
||||
|
||||
const Options: React.FC = () => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [defaultValues, setDefaultValues] = useState<OptionsFormValuesProperties>({
|
||||
const [extensionConfig, setExtensionConfig] = useState<ExtensionConfigProperties>({
|
||||
apikey: '',
|
||||
autocopy: true,
|
||||
history: false,
|
||||
@@ -18,38 +27,49 @@ const Options: React.FC = () => {
|
||||
useEffect(() => {
|
||||
async function getSavedSettings(): Promise<void> {
|
||||
const { settings = {} } = await getExtensionSettings();
|
||||
const customHost: string = settings.customhost || defaultValues.customhost;
|
||||
const advancedSettings: boolean = settings.advanced || defaultValues.advanced;
|
||||
// eslint-disable-next-line no-nested-ternary
|
||||
const customHost: string = settings.customhost
|
||||
? isValidUrl(settings.customurl)
|
||||
? settings.customhost
|
||||
: extensionConfig.customhost
|
||||
: extensionConfig.customhost;
|
||||
const advancedSettings: boolean = settings.advanced || extensionConfig.advanced;
|
||||
|
||||
// inject existing keys (if field doesn't exist, use default)
|
||||
const defaultFormValues: OptionsFormValuesProperties = {
|
||||
apikey: settings.apikey || defaultValues.apikey,
|
||||
const defaultExtensionConfig: ExtensionConfigProperties = {
|
||||
apikey: settings.apikey || extensionConfig.apikey,
|
||||
autocopy: Object.prototype.hasOwnProperty.call(settings, 'autocopy')
|
||||
? settings.autocopy
|
||||
: defaultValues.autocopy,
|
||||
: extensionConfig.autocopy,
|
||||
history: Object.prototype.hasOwnProperty.call(settings, 'history')
|
||||
? settings.history
|
||||
: defaultValues.history,
|
||||
advanced: customHost.trim().length > 0 ? advancedSettings : defaultValues.advanced, // disable `advance` if customhost is not set
|
||||
customhost: advancedSettings === true ? customHost : defaultValues.customhost, // drop customhost value if `advanced` is false
|
||||
: extensionConfig.history,
|
||||
advanced: customHost.trim().length > 0 ? advancedSettings : extensionConfig.advanced, // disable `advance` if customhost is not set
|
||||
customhost:
|
||||
// eslint-disable-next-line no-nested-ternary
|
||||
advancedSettings === true
|
||||
? customHost.endsWith('/')
|
||||
? customHost.slice(0, -1)
|
||||
: customHost
|
||||
: extensionConfig.customhost, // drop customhost value if `advanced` is false
|
||||
};
|
||||
|
||||
setDefaultValues(defaultFormValues);
|
||||
setExtensionConfig(defaultExtensionConfig);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
getSavedSettings();
|
||||
}, [
|
||||
defaultValues.apikey,
|
||||
defaultValues.autocopy,
|
||||
defaultValues.history,
|
||||
defaultValues.advanced,
|
||||
defaultValues.customhost,
|
||||
extensionConfig.apikey,
|
||||
extensionConfig.autocopy,
|
||||
extensionConfig.history,
|
||||
extensionConfig.advanced,
|
||||
extensionConfig.customhost,
|
||||
]); // dependencies
|
||||
|
||||
return (
|
||||
<BodyWrapper>
|
||||
<div id="options">{!loading ? <OptionsForm defaultValues={defaultValues} /> : <Loader />}</div>
|
||||
<div id="options">{!loading ? <OptionsForm extensionConfig={extensionConfig} /> : <Loader />}</div>
|
||||
</BodyWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,11 +2,18 @@ import React, { useEffect } from 'react';
|
||||
import { withFormik, Field, Form, FormikBag, FormikProps, FormikErrors } from 'formik';
|
||||
|
||||
import Icon from '../components/Icon';
|
||||
import {
|
||||
Kutt,
|
||||
SuccessfulApiKeyCheckProperties,
|
||||
ApiErroredProperties,
|
||||
GetUserSettingsBodyProperties,
|
||||
} from '../Background';
|
||||
import { isValidUrl } from '../util/tabs';
|
||||
import messageUtil from '../util/mesageUtil';
|
||||
import { ExtensionConfigProperties } from './Options';
|
||||
import { CHECK_API_KEY } from '../Background/constants';
|
||||
import { TextField, CheckBox } from '../components/Input';
|
||||
import { updateExtensionSettings } from '../util/settings';
|
||||
import { SuccessfulApiKeyCheckProperties, ApiErroredProperties } from '../Background';
|
||||
|
||||
export type OptionsFormValuesProperties = {
|
||||
apikey: string;
|
||||
@@ -24,12 +31,17 @@ const onSave = (values: OptionsFormValuesProperties): Promise<any> => {
|
||||
|
||||
// Note: The default key-value pairs are not saved to storage without any first interaction
|
||||
const InnerForm: React.FC<FormikProps<OptionsFormValuesProperties>> = props => {
|
||||
const { isSubmitting, handleSubmit, setStatus, status, values } = props;
|
||||
const { isSubmitting, handleSubmit, setFieldValue, setStatus, status, values } = props;
|
||||
|
||||
// on component mount -> set `settings` object
|
||||
useEffect(() => {
|
||||
// Reset `customhost` field on `advanced` untick
|
||||
if (values.advanced === false) {
|
||||
setFieldValue('customhost', '');
|
||||
}
|
||||
|
||||
onSave({ ...values, ...(values.advanced === false && { customhost: '' }) });
|
||||
}, [values]);
|
||||
}, [values, setFieldValue]);
|
||||
|
||||
// run on component update
|
||||
useEffect(() => {
|
||||
@@ -72,15 +84,15 @@ const InnerForm: React.FC<FormikProps<OptionsFormValuesProperties>> = props => {
|
||||
|
||||
// The type of props `OptionsForm` receives
|
||||
type OptionsFormProperties = {
|
||||
defaultValues: OptionsFormValuesProperties;
|
||||
extensionConfig: ExtensionConfigProperties;
|
||||
};
|
||||
|
||||
// Wrap our form with the withFormik HoC
|
||||
const OptionsForm = withFormik<OptionsFormProperties, OptionsFormValuesProperties>({
|
||||
// Transform outer props into form values
|
||||
mapPropsToValues: ({
|
||||
defaultValues: { apikey, autocopy, history, advanced, customhost },
|
||||
}): OptionsFormValuesProperties => {
|
||||
extensionConfig: { apikey, autocopy, history, advanced, customhost },
|
||||
}: OptionsFormProperties): OptionsFormValuesProperties => {
|
||||
return {
|
||||
apikey,
|
||||
autocopy,
|
||||
@@ -96,30 +108,41 @@ const OptionsForm = withFormik<OptionsFormProperties, OptionsFormValuesPropertie
|
||||
if (!values.apikey) {
|
||||
errors.apikey = 'API key missing';
|
||||
}
|
||||
|
||||
// ToDo: restore before on production
|
||||
// else if (values.apikey && values.apikey.trim().length < 40) {
|
||||
// errors.apikey = 'API key must be 40 characters';
|
||||
// } else if (values.apikey && values.apikey.trim().length > 40) {
|
||||
// errors.apikey = 'API key cannot exceed 40 characters';
|
||||
// }
|
||||
// ToDo: add custom domain validation
|
||||
// should begin with `http://` or `https://`
|
||||
// dont end with `/`
|
||||
// no spaces(validate a url)
|
||||
|
||||
if (values.advanced && values.customhost.trim().length <= 0) {
|
||||
errors.customhost = 'Custom URL cannot be empty';
|
||||
}
|
||||
|
||||
if (values.customhost.trim().length > 0) {
|
||||
if (!isValidUrl(values.customhost.trim()) || values.customhost.trim().length < 10) {
|
||||
errors.customhost = 'Please enter a valid url';
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
},
|
||||
|
||||
// for API Key validation only
|
||||
handleSubmit: async (
|
||||
values: OptionsFormValuesProperties,
|
||||
{ apikey, customhost }: OptionsFormValuesProperties,
|
||||
{ setSubmitting, setStatus }: FormikBag<OptionsFormProperties, OptionsFormValuesProperties>
|
||||
) => {
|
||||
// request API validation request
|
||||
// ToDo: attach customdomain (if exist)
|
||||
const response: SuccessfulApiKeyCheckProperties | ApiErroredProperties = await messageUtil.send(CHECK_API_KEY, {
|
||||
apikey: values.apikey.trim(),
|
||||
});
|
||||
const apiKeyValidationBody: GetUserSettingsBodyProperties = {
|
||||
apikey: apikey.trim(),
|
||||
hostUrl: customhost.trim().length > 0 ? customhost.trim() : Kutt.hostUrl,
|
||||
};
|
||||
const response: SuccessfulApiKeyCheckProperties | ApiErroredProperties = await messageUtil.send(
|
||||
CHECK_API_KEY,
|
||||
apiKeyValidationBody
|
||||
);
|
||||
|
||||
if (!response.error) {
|
||||
// set top-level status
|
||||
|
||||
@@ -2,11 +2,11 @@ import React, { useState } from 'react';
|
||||
|
||||
import Icon from '../components/Icon';
|
||||
import messageUtil from '../util/mesageUtil';
|
||||
import { UserConfigProperties, SetPageReloadFlagProperties } from './Popup';
|
||||
import { openExtOptionsPage } from '../util/tabs';
|
||||
import { CHECK_API_KEY } from '../Background/constants';
|
||||
import { updateExtensionSettings } from '../util/settings';
|
||||
import { SuccessfulApiKeyCheckProperties, ApiErroredProperties, GetUserSettingsBodyProperties } from '../Background';
|
||||
import { UserConfigProperties, SetPageReloadFlagProperties } from './Popup';
|
||||
|
||||
type SetLoadingProperties = React.Dispatch<React.SetStateAction<boolean>>;
|
||||
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { UserSettingsResponseProperties } from '../Background';
|
||||
import PopupBody, { ProcessedRequestProperties } from './PopupBody';
|
||||
import { Kutt, UserSettingsResponseProperties } from '../Background';
|
||||
import { getExtensionSettings } from '../util/settings';
|
||||
import BodyWrapper from '../components/BodyWrapper';
|
||||
import Loader from '../components/Loader';
|
||||
import PopupForm from './PopupForm';
|
||||
import PopupHeader from './Header';
|
||||
import PopupBody, { ProcessedRequestProperties } from './PopupBody';
|
||||
|
||||
import './styles.scss';
|
||||
import { openExtOptionsPage } from '../util/tabs';
|
||||
import { openExtOptionsPage, isValidUrl } from '../util/tabs';
|
||||
|
||||
export enum Kutt {
|
||||
hostDomain = 'kutt.it',
|
||||
hostUrl = 'https://kutt.it',
|
||||
}
|
||||
type HostProperties = {
|
||||
hostDomain: string;
|
||||
hostUrl: string;
|
||||
};
|
||||
|
||||
type DomainOptionsProperties = {
|
||||
option: string;
|
||||
@@ -33,7 +33,7 @@ export type ProcessRequestProperties = React.Dispatch<
|
||||
export type UserConfigProperties = {
|
||||
apikey: string;
|
||||
domainOptions: DomainOptionsProperties[];
|
||||
host: typeof Kutt;
|
||||
host: HostProperties;
|
||||
};
|
||||
|
||||
export type SetPageReloadFlagProperties = React.Dispatch<React.SetStateAction<boolean>>;
|
||||
@@ -67,7 +67,7 @@ const Popup: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
let defaultHost = Kutt;
|
||||
let defaultHost: HostProperties = Kutt;
|
||||
|
||||
// If `advanced` field is true
|
||||
if (Object.prototype.hasOwnProperty.call(settings, 'advanced') && settings.advanced) {
|
||||
@@ -75,7 +75,7 @@ const Popup: React.FC = () => {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(settings, 'customhost') &&
|
||||
settings.customhost.trim().length > 0 &&
|
||||
(settings.customhost.startsWith('http://') || settings.customhost.startsWith('https://'))
|
||||
isValidUrl(settings.customurl)
|
||||
) {
|
||||
defaultHost = {
|
||||
hostDomain: settings.customhost
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import React from 'react';
|
||||
import { withFormik, Field, Form, FormikBag, FormikProps, FormikErrors } from 'formik';
|
||||
|
||||
import messageUtil from '../util/mesageUtil';
|
||||
import { UserConfigProperties, ProcessRequestProperties } from './Popup';
|
||||
import { getCurrentTab } from '../util/tabs';
|
||||
|
||||
import { SHORTEN_URL } from '../Background/constants';
|
||||
import { SelectField, TextField } from '../components/Input';
|
||||
import {
|
||||
ApiBodyProperties,
|
||||
SuccessfulShortenStatusProperties,
|
||||
ApiErroredProperties,
|
||||
ShortUrlActionBodyProperties,
|
||||
} from '../Background';
|
||||
import messageUtil from '../util/mesageUtil';
|
||||
import { getCurrentTab, isValidUrl } from '../util/tabs';
|
||||
import { SHORTEN_URL } from '../Background/constants';
|
||||
import { SelectField, TextField } from '../components/Input';
|
||||
import { ProcessRequestProperties, UserConfigProperties } from './Popup';
|
||||
|
||||
type PopupFormValuesProperties = {
|
||||
password: string;
|
||||
@@ -120,9 +119,9 @@ const PopupForm = withFormik<PopupFormProperties, PopupFormValuesProperties>({
|
||||
const tabs = await getCurrentTab();
|
||||
const target: string | null = (tabs.length > 0 && tabs[0].url) || null;
|
||||
|
||||
if (!target || !target.startsWith('http')) {
|
||||
if (!target || !isValidUrl(target)) {
|
||||
setLoading(false);
|
||||
// No valid target
|
||||
|
||||
return setRequestProcessed({ error: true, message: 'Not a valid URL' });
|
||||
}
|
||||
|
||||
|
||||
@@ -10,3 +10,10 @@ export function getCurrentTab(): Promise<Tabs.Tab[]> {
|
||||
lastFocusedWindow: true,
|
||||
});
|
||||
}
|
||||
|
||||
export function isValidUrl(url: string): boolean {
|
||||
// https://regex101.com/r/iXVlNL/1/
|
||||
const re = /^(http[s]?:\/\/)(www\.){0,1}[a-zA-Z0-9.-]+\.[a-zA-Z]{2,5}[.]{0,1}/;
|
||||
|
||||
return re.test(url);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user