mirror of
https://github.com/kremalicious/umami.git
synced 2025-02-14 21:10:34 +01:00
Updated profile settings. Refactored locale saving.
This commit is contained in:
parent
814589f6a5
commit
7f598fa84d
@ -1,12 +1,13 @@
|
|||||||
import React, { useState, useRef } from 'react';
|
import React, { useState, useRef } from 'react';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import Globe from 'assets/globe.svg';
|
|
||||||
import useDocumentClick from 'hooks/useDocumentClick';
|
|
||||||
import Menu from './Menu';
|
import Menu from './Menu';
|
||||||
import Button from './Button';
|
import Button from './Button';
|
||||||
import { menuOptions } from 'lib/lang';
|
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 styles from './LanguageButton.module.css';
|
||||||
import useLocale from '../../hooks/useLocale';
|
|
||||||
|
|
||||||
export default function LanguageButton({ menuPosition = 'bottom', menuAlign = 'left' }) {
|
export default function LanguageButton({ menuPosition = 'bottom', menuAlign = 'left' }) {
|
||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
@ -16,7 +17,7 @@ export default function LanguageButton({ menuPosition = 'bottom', menuAlign = 'l
|
|||||||
|
|
||||||
function handleSelect(value) {
|
function handleSelect(value) {
|
||||||
setLocale(value);
|
setLocale(value);
|
||||||
window.localStorage.setItem('locale', value);
|
setItem('umami.locale', value);
|
||||||
setShowMenu(false);
|
setShowMenu(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ export default function WebsiteChart({
|
|||||||
const dateRange = useDateRange(websiteId);
|
const dateRange = useDateRange(websiteId);
|
||||||
const { startDate, endDate, unit, value, modified } = dateRange;
|
const { startDate, endDate, unit, value, modified } = dateRange;
|
||||||
|
|
||||||
|
console.log({ websiteId, dateRange });
|
||||||
|
|
||||||
const { data } = useFetch(
|
const { data } = useFetch(
|
||||||
`/api/website/${websiteId}/pageviews`,
|
`/api/website/${websiteId}/pageviews`,
|
||||||
{
|
{
|
||||||
|
@ -1,24 +1,39 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import PageHeader from 'components/layout/PageHeader';
|
import PageHeader from 'components/layout/PageHeader';
|
||||||
import Button from 'components/common/Button';
|
import Button from 'components/common/Button';
|
||||||
import Modal from 'components/common/Modal';
|
import Modal from 'components/common/Modal';
|
||||||
import Toast from 'components/common/Toast';
|
import Toast from 'components/common/Toast';
|
||||||
import ChangePasswordForm from 'components/forms/ChangePasswordForm';
|
import ChangePasswordForm from 'components/forms/ChangePasswordForm';
|
||||||
|
import DateFilter from 'components/common/DateFilter';
|
||||||
import Dots from 'assets/ellipsis-h.svg';
|
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() {
|
export default function ProfileSettings() {
|
||||||
|
const dispatch = useDispatch();
|
||||||
const user = useSelector(state => state.user);
|
const user = useSelector(state => state.user);
|
||||||
const [changePassword, setChangePassword] = useState(false);
|
const [changePassword, setChangePassword] = useState(false);
|
||||||
const [message, setMessage] = useState();
|
const [message, setMessage] = useState();
|
||||||
const { user_id } = user;
|
const { user_id } = user;
|
||||||
|
const timezone = getTimezone();
|
||||||
|
const dateRange = useDateRange(0);
|
||||||
|
const { startDate, endDate, value } = dateRange;
|
||||||
|
|
||||||
function handleSave() {
|
function handleSave() {
|
||||||
setChangePassword(false);
|
setChangePassword(false);
|
||||||
setMessage(<FormattedMessage id="message.save-success" defaultMessage="Saved successfully." />);
|
setMessage(<FormattedMessage id="message.save-success" defaultMessage="Saved successfully." />);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleDateChange(values) {
|
||||||
|
setItem(`umami.date-range`, values);
|
||||||
|
dispatch(setDateRange(0, values));
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageHeader>
|
<PageHeader>
|
||||||
@ -36,6 +51,21 @@ export default function ProfileSettings() {
|
|||||||
<FormattedMessage id="label.username" defaultMessage="Username" />
|
<FormattedMessage id="label.username" defaultMessage="Username" />
|
||||||
</dt>
|
</dt>
|
||||||
<dd>{user.username}</dd>
|
<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>
|
</dl>
|
||||||
{changePassword && (
|
{changePassword && (
|
||||||
<Modal
|
<Modal
|
||||||
|
3
components/settings/ProfileSettings.module.css
Normal file
3
components/settings/ProfileSettings.module.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.date {
|
||||||
|
display: flex;
|
||||||
|
}
|
@ -1,8 +1,18 @@
|
|||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
import { parseISO } from 'date-fns';
|
||||||
import { getDateRange } from 'lib/date';
|
import { getDateRange } from 'lib/date';
|
||||||
|
import { getItem } from 'lib/web';
|
||||||
|
|
||||||
export function useDateRange(websiteId, defaultDateRange = '7day') {
|
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(
|
return useSelector(
|
||||||
state => state.websites[websiteId]?.dateRange || getDateRange(defaultDateRange),
|
state =>
|
||||||
|
state.websites[websiteId]?.dateRange || globalDefault || getDateRange(defaultDateRange),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
15
lib/web.js
15
lib/web.js
@ -19,7 +19,7 @@ export const apiRequest = (method, url, body) =>
|
|||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
function parseQuery(url, params = {}) {
|
const parseQuery = (url, params = {}) => {
|
||||||
const query = Object.keys(params).reduce((values, key) => {
|
const query = Object.keys(params).reduce((values, key) => {
|
||||||
if (params[key] !== undefined) {
|
if (params[key] !== undefined) {
|
||||||
return values.concat(`${key}=${encodeURIComponent(params[key])}`);
|
return values.concat(`${key}=${encodeURIComponent(params[key])}`);
|
||||||
@ -27,7 +27,7 @@ function parseQuery(url, params = {}) {
|
|||||||
return values;
|
return values;
|
||||||
}, []);
|
}, []);
|
||||||
return query.length ? `${url}?${query.join('&')}` : url;
|
return query.length ? `${url}?${query.join('&')}` : url;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const get = (url, params) => apiRequest('get', parseQuery(url, params));
|
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';
|
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;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React from 'react';
|
||||||
import { IntlProvider } from 'react-intl';
|
import { IntlProvider } from 'react-intl';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { useStore } from 'redux/store';
|
import { useStore } from 'redux/store';
|
||||||
@ -9,17 +9,10 @@ import 'styles/bootstrap-grid.css';
|
|||||||
import 'styles/index.css';
|
import 'styles/index.css';
|
||||||
|
|
||||||
const Intl = ({ children }) => {
|
const Intl = ({ children }) => {
|
||||||
const [locale, setLocale] = useLocale();
|
const [locale] = useLocale();
|
||||||
|
|
||||||
const Wrapper = ({ children }) => <span className={locale}>{children}</span>;
|
const Wrapper = ({ children }) => <span className={locale}>{children}</span>;
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const saved = localStorage.getItem('locale');
|
|
||||||
if (saved) {
|
|
||||||
setLocale(saved);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IntlProvider locale={locale} messages={messages[locale]} textComponent={Wrapper}>
|
<IntlProvider locale={locale} messages={messages[locale]} textComponent={Wrapper}>
|
||||||
{children}
|
{children}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { createSlice } from '@reduxjs/toolkit';
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
|
import { getItem } from 'lib/web';
|
||||||
|
|
||||||
const app = createSlice({
|
const app = createSlice({
|
||||||
name: 'app',
|
name: 'app',
|
||||||
initialState: { locale: 'en-US' },
|
initialState: { locale: getItem('umami.locale') || 'en-US' },
|
||||||
reducers: {
|
reducers: {
|
||||||
updateApp(state, action) {
|
updateApp(state, action) {
|
||||||
state = action.payload;
|
state = action.payload;
|
||||||
|
@ -36,17 +36,6 @@ h6 {
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
#__next {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#__modals {
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
button,
|
||||||
input,
|
input,
|
||||||
select {
|
select {
|
||||||
@ -87,16 +76,28 @@ label:empty {
|
|||||||
|
|
||||||
dt {
|
dt {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
margin: 0 0 5px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dd {
|
dd {
|
||||||
margin: 0 0 10px 0;
|
margin: 0 0 30px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#__next {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#__modals {
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user