Refactored website ordering feature.

This commit is contained in:
Mike Cao 2022-08-04 03:56:30 -07:00
parent 62dce0a8d1
commit 1d4aa7c535
96 changed files with 518 additions and 174 deletions

View File

@ -1,5 +1,5 @@
import { useState } from 'react';
import { FormattedMessage } from 'react-intl';
import { defineMessages, useIntl } from 'react-intl';
import { useRouter } from 'next/router';
import Page from 'components/layout/Page';
import PageHeader from 'components/layout/PageHeader';
@ -7,19 +7,24 @@ import WebsiteList from 'components/pages/WebsiteList';
import Button from 'components/common/Button';
import DashboardSettingsButton from 'components/settings/DashboardSettingsButton';
import useFetch from 'hooks/useFetch';
import useStore from 'store/app';
import useDashboard from 'store/dashboard';
import DashboardEdit from './DashboardEdit';
import styles from './WebsiteList.module.css';
const selector = state => state.dashboard;
const messages = defineMessages({
dashboard: { id: 'label.dashboard', defaultMessage: 'Dashboard' },
more: { id: 'label.more', defaultMessage: 'More' },
});
export default function Dashboard() {
const router = useRouter();
const { id } = router.query;
const userId = id?.[0];
const store = useStore(selector);
const { showCharts, limit } = store;
const dashboard = useDashboard();
const { showCharts, limit, editing } = dashboard;
const [max, setMax] = useState(limit);
const { data } = useFetch('/websites', { params: { user_id: userId } });
const { formatMessage } = useIntl();
function handleMore() {
setMax(max + limit);
@ -32,15 +37,14 @@ export default function Dashboard() {
return (
<Page>
<PageHeader>
<div>
<FormattedMessage id="label.dashboard" defaultMessage="Dashboard" />
</div>
<DashboardSettingsButton />
<div>{formatMessage(messages.dashboard)}</div>
{!editing && <DashboardSettingsButton />}
</PageHeader>
<WebsiteList websites={data} showCharts={showCharts} limit={max} />
{editing && <DashboardEdit data={data} />}
{!editing && <WebsiteList data={data} showCharts={showCharts} limit={max} />}
{max < data.length && (
<Button className={styles.button} onClick={handleMore}>
<FormattedMessage id="label.more" defaultMessage="More" />
{formatMessage(messages.more)}
</Button>
)}
</Page>

View File

@ -0,0 +1,100 @@
import { useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
import useDashboard, { saveDashboard } from 'store/dashboard';
import Button from 'components/common/Button';
import { useMemo } from 'react';
import { orderByWebsiteMap } from 'lib/format';
import styles from './DashboardEdit.module.css';
const messages = defineMessages({
save: { id: 'label.save', defaultMessage: 'Save' },
reset: { id: 'label.reset', defaultMessage: 'Reset' },
cancel: { id: 'label.cancel', defaultMessage: 'Cancel' },
});
const dragId = 'dashboard-website-ordering';
export default function DashboardEdit({ data: websites }) {
const settings = useDashboard();
const { websiteOrder } = settings;
const { formatMessage } = useIntl();
const [order, setOrder] = useState(websiteOrder);
const ordered = useMemo(() => orderByWebsiteMap(websites, order), [websites, order]);
console.log({ order, ordered });
function handleWebsiteDrag({ destination, source }) {
if (!destination || destination.index === source.index) return;
const orderedWebsites = [...ordered];
const [removed] = orderedWebsites.splice(source.index, 1);
orderedWebsites.splice(destination.index, 0, removed);
setOrder(
orderedWebsites.map((i, k) => ({ [i.website_uuid]: k })).reduce((a, b) => ({ ...a, ...b })),
);
}
function handleSave() {
saveDashboard({
editing: false,
websiteOrder: order,
});
}
function handleCancel() {
saveDashboard({ editing: false });
}
function handleReset() {
setOrder({});
saveDashboard({ websiteOrder: {} });
}
return (
<>
<div className={styles.buttons}>
<Button onClick={handleSave} size="small">
{formatMessage(messages.save)}
</Button>
<Button onClick={handleCancel} size="small">
{formatMessage(messages.cancel)}
</Button>
<Button onClick={handleReset} size="small">
{formatMessage(messages.reset)}
</Button>
</div>
<div className={styles.dragActive}>
<DragDropContext onDragEnd={handleWebsiteDrag}>
<Droppable droppableId={dragId}>
{(provided, snapshot) => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
style={{ marginBottom: snapshot.isDraggingOver ? 260 : null }}
>
{ordered.map(({ website_id, name, domain }, index) => (
<Draggable key={website_id} draggableId={`${dragId}-${website_id}`} index={index}>
{provided => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
className={styles.item}
>
<h1>{name}</h1>
<h2>{domain}</h2>
</div>
)}
</Draggable>
))}
</div>
)}
</Droppable>
</DragDropContext>
</div>
</>
);
}

View File

@ -0,0 +1,34 @@
.buttons {
display: flex;
justify-content: flex-end;
gap: 10px;
margin-bottom: 20px;
}
.item {
padding: 20px;
border-radius: 5px;
border: 1px solid var(--gray300);
}
.item + .item {
margin-top: 10px;
}
.item h1 {
font-weight: 600;
font-size: 16px;
}
.item h2 {
font-size: 14px;
color: var(--gray700);
}
.dragActive {
cursor: grab;
}
.dragActive:active {
cursor: grabbing;
}

View File

@ -1,4 +1,3 @@
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
import { FormattedMessage } from 'react-intl';
import Link from 'components/common/Link';
import WebsiteChart from 'components/metrics/WebsiteChart';
@ -6,37 +5,14 @@ import Page from 'components/layout/Page';
import EmptyPlaceholder from 'components/common/EmptyPlaceholder';
import Arrow from 'assets/arrow-right.svg';
import styles from './WebsiteList.module.css';
import useDashboard from 'store/dashboard';
import { orderByWebsiteMap } from 'lib/format';
import { useMemo } from 'react';
import useStore, { setDashboard } from 'store/app';
const selector = state => state.dashboard;
export default function WebsiteList({ data, showCharts, limit }) {
const { websiteOrder } = useDashboard();
export default function WebsiteList({ websites, showCharts, limit }) {
const store = useStore(selector);
const { websiteOrdering, changeOrderMode } = store;
const ordered = useMemo(
() => orderByWebsiteMap(websites, websiteOrdering),
[websites, websiteOrdering],
);
const dragId = 'dashboard-website-ordering';
function handleWebsiteDrag({ destination, source }) {
if (!destination || destination.index === source.index) return;
const orderedWebsites = [...ordered];
const [removed] = orderedWebsites.splice(source.index, 1);
orderedWebsites.splice(destination.index, 0, removed);
setDashboard({
...store,
websiteOrdering: orderedWebsites
.map((i, k) => ({ [i.website_uuid]: k }))
.reduce((a, b) => ({ ...a, ...b })),
});
}
const websites = useMemo(() => orderByWebsiteMap(data, websiteOrder), [data, websiteOrder]);
if (websites.length === 0) {
return (
@ -58,60 +34,19 @@ export default function WebsiteList({ websites, showCharts, limit }) {
}
return (
<div className={changeOrderMode && styles.websiteDragActive}>
{changeOrderMode ? (
<DragDropContext onDragEnd={handleWebsiteDrag}>
<Droppable droppableId={dragId}>
{(provided, snapshot) => (
<div
{...provided.droppableProps}
ref={provided.innerRef}
style={{ marginBottom: snapshot.isDraggingOver ? 260 : null }}
>
{ordered.map(({ website_id, name, domain }, index) =>
index < limit ? (
<Draggable
key={website_id}
draggableId={`${dragId}-${website_id}`}
index={index}
>
{provided => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
className={styles.website}
>
<WebsiteChart
websiteId={website_id}
title={name}
domain={domain}
showChart={changeOrderMode ? false : showCharts}
showLink
/>
</div>
)}
</Draggable>
) : null,
)}
</div>
)}
</Droppable>
</DragDropContext>
) : (
ordered.map(({ website_id, name, domain }, index) =>
index < limit ? (
<div key={website_id} className={styles.website}>
<WebsiteChart
websiteId={website_id}
title={name}
domain={domain}
showChart={showCharts}
showLink
/>
</div>
) : null,
)
<div>
{websites.map(({ website_id, name, domain }, index) =>
index < limit ? (
<div key={website_id} className={styles.website}>
<WebsiteChart
websiteId={website_id}
title={name}
domain={domain}
showChart={showCharts}
showLink
/>
</div>
) : null,
)}
</div>
);

View File

@ -9,12 +9,3 @@
border-bottom: 0;
margin-bottom: 20px;
}
.websiteDragActive {
opacity: 0.6;
cursor: grab;
}
.websiteDragActive:active {
cursor: grabbing;
}

View File

@ -1,57 +1,40 @@
import React from 'react';
import { FormattedMessage } from 'react-intl';
import { defineMessages, useIntl } from 'react-intl';
import MenuButton from 'components/common/MenuButton';
import Gear from 'assets/gear.svg';
import useStore, { setDashboard } from 'store/app';
import Button from 'components/common/Button';
import Check from 'assets/check.svg';
import styles from './DashboardSettingsButton.module.css';
import { saveDashboard } from 'store/dashboard';
const selector = state => state.dashboard;
const messages = defineMessages({
toggleCharts: { id: 'message.toggle-charts', defaultMessage: 'Toggle charts' },
editDashboard: { id: 'message.edit-dashboard', defaultMessage: 'Edit dashboard' },
});
export default function DashboardSettingsButton() {
const settings = useStore(selector);
const { formatMessage } = useIntl();
const menuOptions = [
{
label: <FormattedMessage id="message.toggle-charts" defaultMessage="Toggle charts" />,
label: formatMessage(messages.toggleCharts),
value: 'charts',
},
{
label: <FormattedMessage id="message.edit-dashboard" defaultMessage="Edit dashboard" />,
label: formatMessage(messages.editDashboard),
value: 'order',
},
];
function handleSelect(value) {
if (value === 'charts') {
setDashboard({ ...settings, showCharts: !settings.showCharts });
saveDashboard(state => {
const bs = { showCharts: !state.showCharts };
console.log('WTF', { state, bs });
return bs;
});
}
if (value === 'order') {
setDashboard({ ...settings, changeOrderMode: !settings.changeOrderMode });
saveDashboard({ editing: true });
}
//setDashboard(value);
}
function handleExitChangeOrderMode() {
setDashboard({ ...settings, changeOrderMode: !settings.changeOrderMode });
}
function resetWebsiteOrder() {
setDashboard({ ...settings, websiteOrdering: {} });
}
if (settings.changeOrderMode)
return (
<div className={styles.buttonGroup}>
<Button onClick={resetWebsiteOrder} size="small">
<FormattedMessage id="label.reset-order" defaultMessage="Reset order" />
</Button>
<Button onClick={handleExitChangeOrderMode} size="small" icon={<Check />}>
<FormattedMessage id="label.done" defaultMessage="Done" />
</Button>
</div>
);
return <MenuButton icon={<Gear />} options={menuOptions} onSelect={handleSelect} hideLabel />;
}

View File

@ -1,4 +1,4 @@
import React, { useMemo, useState } from 'react';
import React, { useState } from 'react';
import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import Link from 'components/common/Link';
@ -24,12 +24,8 @@ import Code from 'assets/code.svg';
import LinkIcon from 'assets/link.svg';
import useFetch from 'hooks/useFetch';
import useUser from 'hooks/useUser';
import { orderByWebsiteMap } from 'lib/format';
import useStore from 'store/app';
import styles from './WebsiteSettings.module.css';
const selector = state => state.dashboard;
export default function WebsiteSettings() {
const { user } = useUser();
const [editWebsite, setEditWebsite] = useState();
@ -41,13 +37,8 @@ export default function WebsiteSettings() {
const [saved, setSaved] = useState(0);
const [message, setMessage] = useState();
const store = useStore(selector);
const { websiteOrdering } = store;
const { data } = useFetch('/websites', { params: { include_all: !!user?.is_admin } }, [saved]);
const ordered = useMemo(() => orderByWebsiteMap(data, websiteOrdering), [data, websiteOrdering]);
const Buttons = row => (
<ButtonLayout align="right">
{row.share_id && (
@ -196,7 +187,7 @@ export default function WebsiteSettings() {
<FormattedMessage id="label.add-website" defaultMessage="Add website" />
</Button>
</PageHeader>
<Table columns={user.is_admin ? adminColumns : columns} rows={ordered} empty={empty} />
<Table columns={user.is_admin ? adminColumns : columns} rows={data} empty={empty} />
{editWebsite && (
<Modal title={<FormattedMessage id="label.edit-website" defaultMessage="Edit website" />}>
<WebsiteEditForm values={editWebsite} onSave={handleSave} onClose={handleClose} />

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "هل أنت متأكد من اعادة تعيين الإحصائيات لـ {target}؟",
"message.copied": "تم النسخ!",
"message.delete-warning": "كافة البيانات المرتبطة سيم حذفها ايضا.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "حدث خطأ ما.",
"message.get-share-url": "احصل على رابط المشاركة",
"message.get-tracking-code": "احصل على كود التتبع",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "আপনি কি নিশ্চিত যে আপনি {target} এর পরিসংখ্যান পুনরায় সেট করতে চান?",
"message.copied": "কপি হয়েছে",
"message.delete-warning": "সমস্ত সম্পর্কিত ডেটা পাশাপাশি মুছে ফেলা হবে।",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "কিছু ভুল হয়েছে।",
"message.get-share-url": "শেয়ার ইউআরএল",
"message.get-tracking-code": "ট্র্যাকিং কোড পান",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Segur que vols restablir les estadístiques de {target}?",
"message.copied": "S'ha copiat",
"message.delete-warning": "També s'esborraran totes les dades relacionades.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "S'ha produït un error.",
"message.get-share-url": "Obté l'enllaç per compartir",
"message.get-tracking-code": "Obté el codi de seguiment",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
"message.copied": "Zkopírováno!",
"message.delete-warning": "Všechna související data budou také smazána.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Něco se pokazilo.",
"message.get-share-url": "Získat sdílené URL",
"message.get-tracking-code": "Získat měřící kód",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Er du sikker på at du ville nulstille {target}'s statistikker?",
"message.copied": "Kopieret!",
"message.delete-warning": "Alle tilknyttede data slettes også.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Noget gik galt.",
"message.get-share-url": "Få delings-URL",
"message.get-tracking-code": "Få sporingskode",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Sind Sie sicher, dass Sie die Statistiken von {target} zurücksetzen wollen?",
"message.copied": "In Zwischenablage kopiert!",
"message.delete-warning": "Alle zugehörigen Daten werden ebenfalls gelöscht.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Es ist ein Fehler aufgetreten.",
"message.get-share-url": "Freigabe-URL abrufen",
"message.get-tracking-code": "Erstelle Tracking Kennung",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
"message.copied": "Αντιγράφηκε!",
"message.delete-warning": "Όλα τα σχετικά δεδομένα θα διαγραφούν επίσης.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Κάτι πήγε στραβά.",
"message.get-share-url": "Λήψη URL κοινής χρήσης",
"message.get-tracking-code": "Λήψη κώδικα παρακολούθησης",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Are you sure you want to reset {target}'s statistics?",
"message.copied": "Copied!",
"message.delete-warning": "All associated data will be deleted as well.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Something went wrong.",
"message.get-share-url": "Get share URL",
"message.get-tracking-code": "Get tracking code",

View File

@ -22,10 +22,8 @@
"label.delete-website": "Delete website",
"label.dismiss": "Dismiss",
"label.domain": "Domain",
"label.done": "Done",
"label.edit": "Edit",
"label.edit-account": "Edit account",
"label.edit-dashboard": "Edit dashboard",
"label.edit-website": "Edit website",
"label.enable-share-url": "Enable share URL",
"label.invalid": "Invalid",
@ -49,7 +47,6 @@
"label.refresh": "Refresh",
"label.required": "Required",
"label.reset": "Reset",
"label.reset-order": "Reset order",
"label.reset-website": "Reset statistics",
"label.save": "Save",
"label.settings": "Settings",
@ -71,6 +68,7 @@
"message.confirm-reset": "Are you sure you want to reset {target}'s statistics?",
"message.copied": "Copied!",
"message.delete-warning": "All associated data will be deleted as well.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Something went wrong.",
"message.get-share-url": "Get share URL",
"message.get-tracking-code": "Get tracking code",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "¿Seguro que deseas restablecer las estadísticas de {target}?",
"message.copied": "¡Copiado!",
"message.delete-warning": "Toda la información relacionada será eliminada.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Algo falló.",
"message.get-share-url": "Obtener URL para compartir",
"message.get-tracking-code": "Obtener código de rastreo",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "آیا از بازنشانی آمار {target} مطمئن هستید?",
"message.copied": "کپی شد!",
"message.delete-warning": "همه‌ی داده‌های مرتبط هم حذف خواهد شد.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "مشکلی پیش آمده است.",
"message.get-share-url": "دریافت URL برای اشتراک گذاری",
"message.get-tracking-code": "گرفتن کد رهگیری",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Haluatko varmasti poistaa sivuston {target} tilastot?",
"message.copied": "Kopioitu!",
"message.delete-warning": "Kaikki siihen liittyvät tiedot poistetaan.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Jotain meni pieleen.",
"message.get-share-url": "Hanki jakamisen URL-osoite",
"message.get-tracking-code": "Hanki seurantakoodi",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
"message.copied": "Avrita!",
"message.delete-warning": "Øll data ið er knýtt at verður eisini strika.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Okkurt bleiv gali.",
"message.get-share-url": "Fá leinku sum tú kanst deila",
"message.get-tracking-code": "Fá sporings kotu",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Êtes-vous sûr de vouloir réinistialiser les statistiques de {target} ?",
"message.copied": "Copié !",
"message.delete-warning": "Toutes les données associées seront également supprimées.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Un problème est survenu.",
"message.get-share-url": "Obtenir l'URL de partage",
"message.get-tracking-code": "Obtenir le code de suivi",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Tes a certeza de querer restablecer as estatísticas de {target}?",
"message.copied": "Copiado!",
"message.delete-warning": "Tamén serán borrados tódolos datos asociados.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Houbo un fallo.",
"message.get-share-url": "Obter URL de compartición",
"message.get-tracking-code": "Obter código de seguimento",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
"message.copied": "הועתק!",
"message.delete-warning": "כל המידע המקושר יימחק",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "משהו השתבש",
"message.get-share-url": "קבלת URL שיתוף",
"message.get-tracking-code": "קבלת קוד מעקב",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
"message.copied": "कॉपी हो गया!",
"message.delete-warning": "सभी संबद्ध डेटा को भी हटा दिया जाएगा।",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "कुछ गलत हो गया।",
"message.get-share-url": "शेयर URL प्राप्त करें",
"message.get-tracking-code": "ट्रैकिंग कोड प्राप्त करें",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
"message.copied": "Kimásolva!",
"message.delete-warning": "Minden társított adat törlésre kerül.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Valami baj történt.",
"message.get-share-url": "Megosztási URL kimásolása",
"message.get-tracking-code": "Követési kód kimásolása",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Anda yakin ingin mengatur ulang statistik {target}?",
"message.copied": "Tersalin!",
"message.delete-warning": "Semua data terkait juga akan dihapus.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Ada yang salah.",
"message.get-share-url": "Dapatkan URL berbagi",
"message.get-tracking-code": "Dapatkan kode pelacakan",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Sei sicuro di voler azzerare le statistiche di {target}?",
"message.copied": "Copiato!",
"message.delete-warning": "Saranno eliminati anche tutti i dati associati.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Si è verificato un errore.",
"message.get-share-url": "Ottieni l'URL di condivisione",
"message.get-tracking-code": "Ottieni il codice di tracking",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
"message.copied": "コピーしました!",
"message.delete-warning": "関連するすべてのデータも削除されます。",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "問題が発生しました。",
"message.get-share-url": "共有リンクを取得",
"message.get-tracking-code": "トラッキングコードを取得",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
"message.copied": "복사했습니다!",
"message.delete-warning": "관련된 모든 데이터도 삭제됩니다.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "오류가 발생하였습니다.",
"message.get-share-url": "공유 URL 가져오기",
"message.get-tracking-code": "추적 코드 가져오기",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Are esate tikri, jog norite atstatyti svetainės {target} statistikos duomenis?",
"message.copied": "Nukopijuota!",
"message.delete-warning": "Visi susiję duomenys taip pat bus ištrinti.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Kažkas įvyko ne taip.",
"message.get-share-url": "Gauti bendrinimo nuorodą",
"message.get-tracking-code": "Gauti sekimo kodą",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
"message.copied": "Хуулсан!",
"message.delete-warning": "Үүнтэй холбоотой бүх өгөгдөл устах болно.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Ямар нэг зүйл буруу боллоо.",
"message.get-share-url": "Хуваалцах холбоос авах",
"message.get-tracking-code": "Мөрдөх код авах",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
"message.copied": "Disalin!",
"message.delete-warning": "Semua data yang berkaitan juga akan dihapuskan.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Ada yang tidak kena.",
"message.get-share-url": "Dapatkan URL berkongsi",
"message.get-tracking-code": "Dapatkan kod penjejakan",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Er du sikker på at du vil nullstille {target}'s statistikk?",
"message.copied": "Kopiert!",
"message.delete-warning": "Alle tilknyttede data slettes også.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Noe gikk galt.",
"message.get-share-url": "Få delings-URL",
"message.get-tracking-code": "Få sporingskode",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Weet je zeker dat je de statistieken van {target} opnieuw wilt instellen?",
"message.copied": "Gekopiëerd!",
"message.delete-warning": "Alle verwante gegezens zullen ook verwijderd worden.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Er is iets misgegaan.",
"message.get-share-url": "Openbare URL",
"message.get-tracking-code": "Tracking code",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Czy na pewno chcesz zresetować statystyki {target}?",
"message.copied": "Skopiowano!",
"message.delete-warning": "Wszystkie powiązane dane również zostaną usunięte.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Coś poszło nie tak.",
"message.get-share-url": "Uzyskaj adres URL udostępniania",
"message.get-tracking-code": "Pobierz kod śledzenia",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Você tem certeza que deseja redefinir as estatísticas de {target}?",
"message.copied": "Copiado!",
"message.delete-warning": "Todos os dados associados também serão eliminados.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Ocorreu um erro.",
"message.get-share-url": "Obter link de compartilhamento",
"message.get-tracking-code": "Obter código de rastreamento",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Tem a certeza que pretende restaurar as estatísticas de {target}?",
"message.copied": "Copiado!",
"message.delete-warning": "Todos os dados associados também serão eliminados.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Ocorreu um erro.",
"message.get-share-url": "Obter link de partilha",
"message.get-tracking-code": "Obter código de rastreamento",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Sunteți sigur că doriți să resetați statisticile pentru {target}?",
"message.copied": "Copiat!",
"message.delete-warning": "Toate datele asociate vor fi șterse, de asemenea.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Ceva n-a mers bine.",
"message.get-share-url": "Obține adresa URL de partajare",
"message.get-tracking-code": "Obține codul de urmărire",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Вы уверены, что хотите сбросить статистику {target}?",
"message.copied": "Скопировано!",
"message.delete-warning": "Все связанные данные будут также удалены.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Что-то пошло не так.",
"message.get-share-url": "Получить публичную ссылку",
"message.get-tracking-code": "Получить код отслеживания",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
"message.copied": "Skopírované!",
"message.delete-warning": "Všetky príbuzné data budu tiež zmazané.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Niečo sa pokazilo.",
"message.get-share-url": "Získať zdielané URL",
"message.get-tracking-code": "Získať tracking kód",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
"message.copied": "Kopirano!",
"message.delete-warning": "Izbrisani bodo tudi vsi povezani podatki.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Prišlo je do napake.",
"message.get-share-url": "Pridobi URL za skupno rabo",
"message.get-tracking-code": "Pridobi kodo za sledenje",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Är du säker på att du vill återställa statistiken för {target}?",
"message.copied": "Kopierad!",
"message.delete-warning": "All tillhörande data kommer också raderas.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Något gick fel.",
"message.get-share-url": "Visa delnings-URL",
"message.get-tracking-code": "Visa spårningskod",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
"message.copied": "நகலெடுக்கப்பட்டது!",
"message.delete-warning": "தொடர்புடைய எல்லா தரவும் நீக்கப்படும்.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "ஏதோ தவறு நடந்துவிட்டது.",
"message.get-share-url": "கள முகவரியை ஐப் பெறுக",
"message.get-tracking-code": "கண்காணிப்பு குறியீட்டைப் பெறுக",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "คุณแน่ใจหรือไม่ว่าต้องการรีเซตข้อมูลสถิติของ {target} ?",
"message.copied": "คัดลอกแล้ว!",
"message.delete-warning": "ข้อมูลที่เกี่ยวข้องทั้งหมดจะถูกลบ.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "เกิดข้อผิดพลาด.",
"message.get-share-url": "รับลิงก์สำหรับแชร์",
"message.get-tracking-code": "รับโค้ดสำหรับใช้ติดตาม",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
"message.copied": "Panoya kopyalandı!",
"message.delete-warning": "İlişkili tüm veriler de silinecektir.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Bir şeyler ters gitti!",
"message.get-share-url": "Paylaşım adresini al",
"message.get-tracking-code": "İzleme kodunu al",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Ви впевнені, що бажаєте скинути статистику для {target}?",
"message.copied": "Скопійовано!",
"message.delete-warning": "Усі пов'язані дані будуть видалені також.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Щось пішло не так.",
"message.get-share-url": "Отримати публічне посилання",
"message.get-tracking-code": "Отримати код для відслідковування",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "کیا آپ واقعی {target} کے اعدادوشمار کو دوبارہ ترتیب دینا چاہتے ہیں؟",
"message.copied": "کاپی کیا گیا!",
"message.delete-warning": "تمام متعلقہ ڈیٹا بھی حذف کر دیا جائے گا۔",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "کچھ غلط ہو گیا.",
"message.get-share-url": "شیئر URL حاصل کریں",
"message.get-tracking-code": "ٹریکنگ کوڈ حاصل کریں",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "Bạn có chắc chắn muốn tái thiết lập thống kê {target}?",
"message.copied": "Đã sao chép!",
"message.delete-warning": "Tất cả các dữ liệu liên quan cũng sẽ bị xoá.",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "Đã xảy ra lỗi.",
"message.get-share-url": "Lấy URL chia sẻ",
"message.get-tracking-code": "Lấy mã theo dõi",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "您确定要重置 {target} 的数据吗?",
"message.copied": "复制成功!",
"message.delete-warning": "所有相关数据将会被删除。",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "出现错误。",
"message.get-share-url": "获取共享链接",
"message.get-tracking-code": "获取跟踪代码",

View File

@ -68,6 +68,7 @@
"message.confirm-reset": "您確定要重置 {target} 的數據嗎?",
"message.copied": "複製成功!",
"message.delete-warning": "所有相關數據將會被刪除。",
"message.edit-dashboard": "Edit dashboard",
"message.failure": "出現錯誤。",
"message.get-share-url": "獲得分享連結",
"message.get-tracking-code": "獲得追蹤代碼",

View File

@ -61,10 +61,17 @@ export const setItem = (key, data, session) => {
}
};
export const getItem = (key, session) =>
typeof window !== 'undefined'
? JSON.parse((session ? sessionStorage : localStorage).getItem(key) || null)
: null;
export const getItem = (key, session) => {
if (typeof window !== 'undefined') {
const value = (session ? sessionStorage : localStorage).getItem(key);
if (value !== 'undefined') {
return JSON.parse(value);
}
}
return null;
};
export const removeItem = (key, session) => {
if (typeof window !== 'undefined') {

View File

@ -477,6 +477,12 @@
"value": "كافة البيانات المرتبطة سيم حذفها ايضا."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "সমস্ত সম্পর্কিত ডেটা পাশাপাশি মুছে ফেলা হবে।"
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "També s'esborraran totes les dades relacionades."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "Všechna související data budou také smazána."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "Alle tilknyttede data slettes også."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "Alle zugehörigen Daten werden ebenfalls gelöscht."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "Όλα τα σχετικά δεδομένα θα διαγραφούν επίσης."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "All associated data will be deleted as well."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "All associated data will be deleted as well."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "Toda la información relacionada será eliminada."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "همه‌ی داده‌های مرتبط هم حذف خواهد شد."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "Kaikki siihen liittyvät tiedot poistetaan."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "Øll data ið er knýtt at verður eisini strika."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -473,6 +473,12 @@
"value": "Toutes les données associées seront également supprimées."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "Tamén serán borrados tódolos datos asociados."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -469,6 +469,12 @@
"value": "כל המידע המקושר יימחק"
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "सभी संबद्ध डेटा को भी हटा दिया जाएगा।"
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -481,6 +481,12 @@
"value": "Minden társított adat törlésre kerül."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -445,6 +445,12 @@
"value": "Semua data terkait juga akan dihapus."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -481,6 +481,12 @@
"value": "Saranno eliminati anche tutti i dati associati."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -449,6 +449,12 @@
"value": "関連するすべてのデータも削除されます。"
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -449,6 +449,12 @@
"value": "관련된 모든 데이터도 삭제됩니다."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -602,6 +602,12 @@
"value": "Visi susiję duomenys taip pat bus ištrinti."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -485,6 +485,12 @@
"value": "Үүнтэй холбоотой бүх өгөгдөл устах болно."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -469,6 +469,12 @@
"value": "Semua data yang berkaitan juga akan dihapuskan."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -481,6 +481,12 @@
"value": "Alle tilknyttede data slettes også."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "Alle verwante gegezens zullen ook verwijderd worden."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "Wszystkie powiązane dane również zostaną usunięte."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -481,6 +481,12 @@
"value": "Todos os dados associados também serão eliminados."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -481,6 +481,12 @@
"value": "Todos os dados associados também serão eliminados."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "Toate datele asociate vor fi șterse, de asemenea."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -453,6 +453,12 @@
"value": "Все связанные данные будут также удалены."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "Všetky príbuzné data budu tiež zmazané."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "Izbrisani bodo tudi vsi povezani podatki."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -481,6 +481,12 @@
"value": "All tillhörande data kommer också raderas."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -477,6 +477,12 @@
"value": "தொடர்புடைய எல்லா தரவும் நீக்கப்படும்."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -473,6 +473,12 @@
"value": "ข้อมูลที่เกี่ยวข้องทั้งหมดจะถูกลบ."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -449,6 +449,12 @@
"value": "İlişkili tüm veriler de silinecektir."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -453,6 +453,12 @@
"value": "Усі пов'язані дані будуть видалені також."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -481,6 +481,12 @@
"value": "تمام متعلقہ ڈیٹا بھی حذف کر دیا جائے گا۔"
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -469,6 +469,12 @@
"value": "Tất cả các dữ liệu liên quan cũng sẽ bị xoá."
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -457,6 +457,12 @@
"value": "所有相关数据将会被删除。"
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -457,6 +457,12 @@
"value": "所有相關數據將會被刪除。"
}
],
"message.edit-dashboard": [
{
"type": 0,
"value": "Edit dashboard"
}
],
"message.failure": [
{
"type": 0,

View File

@ -1,25 +1,10 @@
import create from 'zustand';
import {
DASHBOARD_CONFIG,
DEFAULT_LOCALE,
DEFAULT_THEME,
LOCALE_CONFIG,
THEME_CONFIG,
DEFAULT_WEBSITE_LIMIT,
} from 'lib/constants';
import { getItem, setItem } from 'lib/web';
export const defaultDashboardConfig = {
showCharts: true,
limit: DEFAULT_WEBSITE_LIMIT,
websiteOrdering: {},
changeOrderMode: false,
};
import { DEFAULT_LOCALE, DEFAULT_THEME, LOCALE_CONFIG, THEME_CONFIG } from 'lib/constants';
import { getItem } from 'lib/web';
const initialState = {
locale: getItem(LOCALE_CONFIG) || DEFAULT_LOCALE,
theme: getItem(THEME_CONFIG) || DEFAULT_THEME,
dashboard: getItem(DASHBOARD_CONFIG) || defaultDashboardConfig,
shareToken: null,
user: null,
config: null,
@ -43,11 +28,6 @@ export function setUser(user) {
store.setState({ user });
}
export function setDashboard(dashboard) {
store.setState({ dashboard });
setItem(DASHBOARD_CONFIG, dashboard);
}
export function setConfig(config) {
store.setState({ config });
}

21
store/dashboard.js Normal file
View File

@ -0,0 +1,21 @@
import create from 'zustand';
import { DASHBOARD_CONFIG, DEFAULT_WEBSITE_LIMIT } from 'lib/constants';
import { getItem, setItem } from 'lib/web';
export const initialState = {
showCharts: true,
limit: DEFAULT_WEBSITE_LIMIT,
websiteOrder: {},
editing: false,
};
const store = create(() => ({ ...initialState, ...getItem(DASHBOARD_CONFIG) }));
export function saveDashboard(settings) {
const state = typeof settings === 'function' ? settings(store.getState()) : settings;
store.setState(state);
setItem(DASHBOARD_CONFIG, store.getState());
}
export default store;