Updated profile settings. Refactored locale saving.

This commit is contained in:
Mike Cao 2020-09-17 00:17:11 -07:00
parent 814589f6a5
commit 7f598fa84d
9 changed files with 82 additions and 30 deletions

View File

@ -1,12 +1,13 @@
import React, { useState, useRef } from 'react';
import Head from 'next/head';
import Globe from 'assets/globe.svg';
import useDocumentClick from 'hooks/useDocumentClick';
import Menu from './Menu';
import Button from './Button';
import { menuOptions } from 'lib/lang';
import { setItem } from 'lib/web';
import useLocale from 'hooks/useLocale';
import useDocumentClick from 'hooks/useDocumentClick';
import Globe from 'assets/globe.svg';
import styles from './LanguageButton.module.css';
import useLocale from '../../hooks/useLocale';
export default function LanguageButton({ menuPosition = 'bottom', menuAlign = 'left' }) {
const [showMenu, setShowMenu] = useState(false);
@ -16,7 +17,7 @@ export default function LanguageButton({ menuPosition = 'bottom', menuAlign = 'l
function handleSelect(value) {
setLocale(value);
window.localStorage.setItem('locale', value);
setItem('umami.locale', value);
setShowMenu(false);
}

View File

@ -23,6 +23,8 @@ export default function WebsiteChart({
const dateRange = useDateRange(websiteId);
const { startDate, endDate, unit, value, modified } = dateRange;
console.log({ websiteId, dateRange });
const { data } = useFetch(
`/api/website/${websiteId}/pageviews`,
{

View File

@ -1,24 +1,39 @@
import React, { useState } from 'react';
import { FormattedMessage } from 'react-intl';
import { useSelector } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import PageHeader from 'components/layout/PageHeader';
import Button from 'components/common/Button';
import Modal from 'components/common/Modal';
import Toast from 'components/common/Toast';
import ChangePasswordForm from 'components/forms/ChangePasswordForm';
import DateFilter from 'components/common/DateFilter';
import Dots from 'assets/ellipsis-h.svg';
import { getTimezone } from 'lib/date';
import { setItem } from 'lib/web';
import { useDateRange } from 'hooks/useDateRange';
import { setDateRange } from 'redux/actions/websites';
import styles from './ProfileSettings.module.css';
export default function ProfileSettings() {
const dispatch = useDispatch();
const user = useSelector(state => state.user);
const [changePassword, setChangePassword] = useState(false);
const [message, setMessage] = useState();
const { user_id } = user;
const timezone = getTimezone();
const dateRange = useDateRange(0);
const { startDate, endDate, value } = dateRange;
function handleSave() {
setChangePassword(false);
setMessage(<FormattedMessage id="message.save-success" defaultMessage="Saved successfully." />);
}
function handleDateChange(values) {
setItem(`umami.date-range`, values);
dispatch(setDateRange(0, values));
}
return (
<>
<PageHeader>
@ -36,6 +51,21 @@ export default function ProfileSettings() {
<FormattedMessage id="label.username" defaultMessage="Username" />
</dt>
<dd>{user.username}</dd>
<dt>
<FormattedMessage id="label.timezone" defaultMessage="Timezone" />
</dt>
<dd>{timezone}</dd>
<dt>
<FormattedMessage id="label.default-date-range" defaultMessage="Default date range" />
</dt>
<dd className={styles.date}>
<DateFilter
value={value}
startDate={startDate}
endDate={endDate}
onChange={handleDateChange}
/>
</dd>
</dl>
{changePassword && (
<Modal

View File

@ -0,0 +1,3 @@
.date {
display: flex;
}

View File

@ -1,8 +1,18 @@
import { useSelector } from 'react-redux';
import { parseISO } from 'date-fns';
import { getDateRange } from 'lib/date';
import { getItem } from 'lib/web';
export function useDateRange(websiteId, defaultDateRange = '7day') {
const globalDefault = getItem('umami.date-range');
if (globalDefault) {
globalDefault.startDate = parseISO(globalDefault.startDate);
globalDefault.endDate = parseISO(globalDefault.endDate);
}
return useSelector(
state => state.websites[websiteId]?.dateRange || getDateRange(defaultDateRange),
state =>
state.websites[websiteId]?.dateRange || globalDefault || getDateRange(defaultDateRange),
);
}

View File

@ -19,7 +19,7 @@ export const apiRequest = (method, url, body) =>
return null;
});
function parseQuery(url, params = {}) {
const parseQuery = (url, params = {}) => {
const query = Object.keys(params).reduce((values, key) => {
if (params[key] !== undefined) {
return values.concat(`${key}=${encodeURIComponent(params[key])}`);
@ -27,7 +27,7 @@ function parseQuery(url, params = {}) {
return values;
}, []);
return query.length ? `${url}?${query.join('&')}` : url;
}
};
export const get = (url, params) => apiRequest('get', parseQuery(url, params));
@ -62,3 +62,14 @@ export const doNotTrack = () => {
return dnt === true || dnt === 1 || dnt === 'yes' || dnt === '1';
};
export const setItem = (key, data, session) => {
if (typeof window !== 'undefined') {
(session ? sessionStorage : localStorage).setItem(key, JSON.stringify(data));
}
};
export const getItem = (key, session) =>
typeof window !== 'undefined'
? JSON.parse((session ? sessionStorage : localStorage).getItem(key))
: null;

View File

@ -1,4 +1,4 @@
import React, { useEffect } from 'react';
import React from 'react';
import { IntlProvider } from 'react-intl';
import { Provider } from 'react-redux';
import { useStore } from 'redux/store';
@ -9,17 +9,10 @@ import 'styles/bootstrap-grid.css';
import 'styles/index.css';
const Intl = ({ children }) => {
const [locale, setLocale] = useLocale();
const [locale] = useLocale();
const Wrapper = ({ children }) => <span className={locale}>{children}</span>;
useEffect(() => {
const saved = localStorage.getItem('locale');
if (saved) {
setLocale(saved);
}
});
return (
<IntlProvider locale={locale} messages={messages[locale]} textComponent={Wrapper}>
{children}

View File

@ -1,8 +1,9 @@
import { createSlice } from '@reduxjs/toolkit';
import { getItem } from 'lib/web';
const app = createSlice({
name: 'app',
initialState: { locale: 'en-US' },
initialState: { locale: getItem('umami.locale') || 'en-US' },
reducers: {
updateApp(state, action) {
state = action.payload;

View File

@ -36,17 +36,6 @@ h6 {
font-weight: 400;
}
#__next {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
}
#__modals {
z-index: 10;
}
button,
input,
select {
@ -87,16 +76,28 @@ label:empty {
dt {
font-weight: 600;
margin: 0 0 5px 0;
}
dd {
margin: 0 0 10px 0;
margin: 0 0 30px 0;
}
main {
flex: 1;
}
#__next {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
}
#__modals {
z-index: 10;
}
.container {
padding: 0;
}