{footerLinks.map((link) =>
diff --git a/src/components/layout/privacy-settings-modal/index.ts b/src/components/layout/privacy-settings-modal/index.ts
new file mode 100644
index 00000000..bc687e6c
--- /dev/null
+++ b/src/components/layout/privacy-settings-modal/index.ts
@@ -0,0 +1 @@
+export { default } from './privacy-settings-modal';
diff --git a/src/components/layout/privacy-settings-modal/privacy-settings-modal.module.scss b/src/components/layout/privacy-settings-modal/privacy-settings-modal.module.scss
new file mode 100644
index 00000000..086fbf98
--- /dev/null
+++ b/src/components/layout/privacy-settings-modal/privacy-settings-modal.module.scss
@@ -0,0 +1,80 @@
+@import '../../../styles/variables.module.scss';
+@import '../../../styles/fonts.module.scss';
+@import '../../button/variants/link-blue.module.scss';
+
+.privacySettingsModalContent {
+ display: flex;
+ flex-direction: column;
+
+ .privacyDescription {
+ margin-bottom: 40px;
+
+ > span {
+ @include font-body-9;
+ color: $color-dark-blue-400;
+ margin: 0;
+ }
+
+ .privacyPolicyButton {
+ @include link-blue;
+ white-space: nowrap;
+ text-decoration: none;
+ }
+
+ .externalLinkIcon {
+ margin-left: 0.5ch;
+ }
+ }
+
+ .checkboxes {
+ display: flex;
+ flex-direction: column;
+ gap: 24px;
+
+ .checkboxContainer {
+ .checkboxTextBlock {
+ gap: 8px;
+ }
+
+ .sentryButton {
+ display: inline-block;
+ margin-right: 0.5ch;
+
+ a {
+ @include link-blue;
+ @include font-link-3;
+ white-space: nowrap;
+ text-decoration: none;
+ }
+ }
+ }
+ }
+
+ @media (min-width: $sm) {
+ .privacyDescription {
+ margin-bottom: 40px;
+
+ > span {
+ @include font-body-6;
+ }
+ }
+
+ .checkboxes {
+ .checkboxContainer {
+ .sentryButton {
+ a {
+ @include font-link-2;
+ }
+ }
+ }
+ }
+ }
+}
+
+.saveSettingsButton {
+ width: 100%;
+
+ @media (min-width: $sm) {
+ width: auto;
+ }
+}
diff --git a/src/components/layout/privacy-settings-modal/privacy-settings-modal.tsx b/src/components/layout/privacy-settings-modal/privacy-settings-modal.tsx
new file mode 100644
index 00000000..8b3b859f
--- /dev/null
+++ b/src/components/layout/privacy-settings-modal/privacy-settings-modal.tsx
@@ -0,0 +1,84 @@
+import { KeyboardEvent, MouseEvent, useState } from 'react';
+import { ALLOW_ANALYTICS, ALLOW_ERROR_REPORTING } from '../../../utils/analytics';
+import { Modal, ModalFooter, ModalHeader } from '../../modal';
+import styles from './privacy-settings-modal.module.scss';
+import Button from '../../button';
+import CheckBox from '../../checkbox';
+import { links } from '../../../utils/links';
+import classNames from 'classnames';
+import ExternalLink from '../../external-link';
+import { images } from '../../../utils';
+
+interface Props {
+ open: boolean;
+ onCancel: () => void;
+ onSubmit: (allowAnalytics: boolean, allowReporting: boolean) => void;
+}
+
+const PrivacySettingsModal = (props: Props) => {
+ const { open, onCancel, onSubmit } = props;
+
+ const storedErrorReportingFlag = localStorage.getItem(ALLOW_ERROR_REPORTING);
+ const storedAnalyticsFlag = localStorage.getItem(ALLOW_ANALYTICS);
+
+ const [allowReporting, setAllowReporting] = useState(() => storedErrorReportingFlag === 'true');
+ const [allowAnalytics, setAllowAnalytics] = useState(() => storedAnalyticsFlag === 'true');
+
+ const handleEvent = (event: KeyboardEvent
| MouseEvent) => {
+ event.stopPropagation();
+ };
+
+ return (
+
+ Privacy Settings
+
+
+
+
+ In order to provide the best services for you, we collect anonymized error data through Sentry and use
+ analytics cookies to improve our products. We do not gather IP address or user agent information.{' '}
+
+
+ Visit our Privacy Policy
+
+
+
+
+
+
+
+
+
+ Sentry
+ {' '}
+
+
+ collects error data to improve the performance and reliability of our services, and helps us identify and
+ fix issues quickly, ensuring a smoother experience for you.
+
+
+
+
+
+ Analytics cookies help us to improve our website by collecting and reporting information on how you use
+ it.
+
+
+
+
+
+
+ onSubmit(allowAnalytics, allowReporting)}
+ >
+ Save Settings
+
+
+
+ );
+};
+
+export default PrivacySettingsModal;
diff --git a/src/components/notifications/storage-full-notification.tsx b/src/components/notifications/storage-full-notification.tsx
index baa53970..0677eead 100644
--- a/src/components/notifications/storage-full-notification.tsx
+++ b/src/components/notifications/storage-full-notification.tsx
@@ -1,7 +1,7 @@
import { useState } from 'react';
import { closeAll } from './notifications';
-import { ERROR_REPORTING_CONSENT_KEY_NAME } from '../../utils';
import styles from './storage-full-notification.module.scss';
+import { ALLOW_ANALYTICS, ALLOW_ERROR_REPORTING } from '../../utils/analytics';
export default function StorageFullNotification() {
const [busy, setBusy] = useState(false);
@@ -18,10 +18,14 @@ export default function StorageFullNotification() {
disabled={busy}
onClick={() => {
setBusy(true);
- const errorReportingValue = window.localStorage.getItem(ERROR_REPORTING_CONSENT_KEY_NAME);
+ const errorReportingValue = window.localStorage.getItem(ALLOW_ERROR_REPORTING);
+ const analyticsValue = window.localStorage.getItem(ALLOW_ANALYTICS);
window.localStorage.clear();
if (errorReportingValue) {
- window.localStorage.setItem(ERROR_REPORTING_CONSENT_KEY_NAME, errorReportingValue);
+ window.localStorage.setItem(ALLOW_ERROR_REPORTING, errorReportingValue);
+ }
+ if (analyticsValue) {
+ window.localStorage.setItem(ALLOW_ANALYTICS, analyticsValue);
}
window.location.reload();
}}
diff --git a/src/index.tsx b/src/index.tsx
index 66a77574..c40b4961 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,29 +1,9 @@
import { createRoot } from 'react-dom/client';
-import * as Sentry from '@sentry/react';
import './index.scss';
import App from './app';
import { mockLocalhostWeb3Provider } from './chain-data';
-import { ERROR_REPORTING_CONSENT_KEY_NAME, isErrorReportingAllowed } from './utils';
-
-const errorReportingValue = localStorage.getItem(ERROR_REPORTING_CONSENT_KEY_NAME);
-if (isErrorReportingAllowed(errorReportingValue) && process.env.REACT_APP_SENTRY_DSN) {
- Sentry.init({
- dsn: process.env.REACT_APP_SENTRY_DSN,
- environment: process.env.REACT_APP_NODE_ENV,
- integrations(integrations) {
- return integrations.filter((integration) => {
- // Integrations can be filtered out here
- // See: https://docs.sentry.io/platforms/javascript/configuration/integrations/default/
- return !['UserAgent'].includes(integration.name);
- });
- },
- beforeSend(event) {
- // Do not collect the user's IP address
- event.user = { ip_address: '0.0.0.0' };
- return event;
- },
- });
-}
+import { canReportErrors, canUseAnalytics, initAnalytics } from './utils/analytics';
+import { initSentry } from './utils/error-reporting';
if (process.env.REACT_APP_NODE_ENV === 'development' && (window as any).ethereum === undefined) {
mockLocalhostWeb3Provider(window);
@@ -35,3 +15,11 @@ const root = createRoot(document.getElementById('root')!);
// in our data hooks triggering 3 times on mount (the third trigger is caused by the memoized smart contracts
// which are included in the useEffect dependency arrays). Because of this, we have decided to turn off strict mode.
root.render( );
+
+if (canReportErrors()) {
+ initSentry();
+}
+
+if (canUseAnalytics()) {
+ initAnalytics();
+}
diff --git a/src/pages/dashboard/unstake-banner/unstake-banner.module.scss b/src/pages/dashboard/unstake-banner/unstake-banner.module.scss
index 123ea9d6..6d3fd227 100644
--- a/src/pages/dashboard/unstake-banner/unstake-banner.module.scss
+++ b/src/pages/dashboard/unstake-banner/unstake-banner.module.scss
@@ -1,44 +1,52 @@
@import '../../../styles/variables.module.scss';
+@import '../../../styles/fonts.module.scss';
.unstakeBanner {
width: 100%;
display: flex;
+ flex-direction: column;
+ gap: 16px;
align-items: center;
justify-content: space-between;
- padding: $space-lg 0;
- border-top: 1px solid rgba(124, 227, 203, 0.4);
- border-bottom: 1px solid rgba(124, 227, 203, 0.4);
- margin-bottom: 2 * $space-xl;
-
- @media (max-width: $max-md) {
- flex-direction: column;
-
- & > *:not(:last-child) {
- margin-bottom: $space-lg;
- }
+ background: linear-gradient(180deg, #fafafa 0%, #f0f4ff 100%);
+ border-top: 1px solid $color-dark-blue-10;
+ border-bottom: 1px solid $color-dark-blue-10;
+ margin: 32px 0;
+ padding: 24px 16px;
+
+ @media (min-width: $sm) {
+ margin: 40px 0 72px 0;
+ padding: 24px;
+ flex-direction: row;
}
}
.unstakeBannerWrap {
display: flex;
align-items: center;
- margin-right: $space-lg;
- @media (max-width: $max-sm) {
- margin-right: 0;
- margin-bottom: $space-md;
+ gap: 16px;
+ @include font-body-10;
+
+ & > svg {
+ color: $color-action-success-600;
+ width: 28px;
+ height: 28px;
}
- & > img {
- margin-right: $space-lg;
+ @media (min-width: $md) {
+ @include font-body-4;
+ gap: 24px;
+
+ & > svg {
+ width: 36px;
+ height: 36px;
+ }
}
}
.buttonPanel {
display: flex;
align-items: center;
-
- & > *:not(:last-child) {
- margin-right: $space-xxl;
- }
+ gap: 32px;
}
diff --git a/src/pages/dashboard/unstake-banner/unstake-banner.tsx b/src/pages/dashboard/unstake-banner/unstake-banner.tsx
index cb4be57b..1cb8efcc 100644
--- a/src/pages/dashboard/unstake-banner/unstake-banner.tsx
+++ b/src/pages/dashboard/unstake-banner/unstake-banner.tsx
@@ -1,10 +1,9 @@
import { useApi3Pool } from '../../../contracts';
import { useChainData } from '../../../chain-data';
-import { images } from '../../../utils';
import Button from '../../../components/button';
-import globalStyles from '../../../styles/global-styles.module.scss';
import styles from './unstake-banner.module.scss';
import { handleTransactionError } from '../../../utils';
+import { CheckCircleFillIcon } from '../../../components/icons';
interface Props {
canUnstakeAndWithdraw: boolean;
@@ -36,16 +35,20 @@ const UnstakeBanner = (props: Props) => {
return (
-
-
-
Your tokens are ready to be unstaked.
-
+
+
Your tokens are ready to be unstaked.
-
+
Unstake
-
+
Unstake and Withdraw
diff --git a/src/pages/history/history.module.scss b/src/pages/history/history.module.scss
index 36a658c9..8a31b277 100644
--- a/src/pages/history/history.module.scss
+++ b/src/pages/history/history.module.scss
@@ -1,53 +1,64 @@
@import '../../styles/variables.module.scss';
+@import '../../styles/fonts.module.scss';
-.filterButton {
- button {
- padding: $space-sm !important;
- text-decoration: none !important;
+h5 {
+ @include font-heading-9;
+ color: $color-dark-blue-100;
+
+ @media (min-width: $sm) {
+ @include font-heading-8;
}
-}
-.active {
- text-underline-offset: $space-xs;
- text-decoration: underline;
+ @media (min-width: $md) {
+ @include font-heading-7;
+ }
}
.header {
- margin-bottom: 80px;
+ margin-bottom: 32px;
@media (min-width: $min-md) {
display: flex;
justify-content: space-between;
+ margin-bottom: 64px;
}
}
-.treasury {
- margin-top: -30px;
-}
-
-.borderBoxHeader {
+.proposalsHeader {
display: flex;
- align-items: center;
- justify-content: space-between;
- transform: translateY(-50%);
+ flex-direction: column;
+ gap: 16px;
+
+ @media (min-width: $sm) {
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-between;
+ }
}
.radioButtons {
display: flex;
align-items: center;
- justify-content: flex-end;
flex-wrap: wrap;
- margin-left: $space-md;
+ gap: 16px;
- & > * {
- margin-right: $space-lg;
+ svg {
+ width: 16px;
+ height: 16px;
+ }
- @media (max-width: $max-md) {
- margin-right: $space-md;
- }
+ label {
+ @include font-body-12;
}
- & > *:last-child {
- margin-right: 0;
+ @media (min-width: $md) {
+ svg {
+ width: 20px;
+ height: 20px;
+ }
+
+ label {
+ @include font-body-9;
+ }
}
}
diff --git a/src/pages/history/history.tsx b/src/pages/history/history.tsx
index b3868e9f..3581633a 100644
--- a/src/pages/history/history.tsx
+++ b/src/pages/history/history.tsx
@@ -5,7 +5,6 @@ import { useQueryParams } from '../../utils';
import { ProposalType } from '../../chain-data/state';
import { historyProposalsSelector, OptionalProposalType } from '../../logic/proposals/selectors';
import { useChainData } from '../../chain-data';
-import BorderedBox from '../../components/bordered-box/bordered-box';
import RadioButton from '../../components/radio-button/radio-button';
import ProposalList from '../proposal-commons/proposal-list';
import styles from './history.module.scss';
@@ -50,27 +49,22 @@ const History = () => {
-
- Past Proposals
-
- setCheckedPrimary(!checkedPrimary)}>
- Primary
-
- setCheckedSecondary(!checkedSecondary)}
- >
- Secondary
-
-
-
- }
- content={