diff --git a/CHANGELOG.md b/CHANGELOG.md index f0f41659..6574158c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,10 @@ The following log documentes the history of the server project. - `WebURL`: the URL to your Dnote server, without the trailing slash. (e.g. `https://my-server.com`) (Please see #290) - `SmtpPort`: the SMTP port. (e.g. `465`) optional - required *if you want to configure email* +#### Added + +- Display version number in the settings (#293) + #### Fixed - Allow to customize the app URL in the emails (#290) diff --git a/Makefile b/Makefile index d32d03ef..a43ed24b 100644 --- a/Makefile +++ b/Makefile @@ -87,13 +87,16 @@ endif # development dev-server: @echo "==> running dev environment" - @(cd ${GOPATH}/src/github.com/dnote/dnote/web && ./scripts/dev.sh) + @(cd ${GOPATH}/src/github.com/dnote/dnote/web && VERSION=master ./scripts/dev.sh) .PHONY: dev-server ## build build-web: +ifndef version + $(error version is required. Usage: make version=0.1.0 build-web) +endif @echo "==> building web" - @(cd ${GOPATH}/src/github.com/dnote/dnote/web && ./scripts/build-prod.sh) + @(cd ${GOPATH}/src/github.com/dnote/dnote/web && VERSION=$(version) ./scripts/build-prod.sh) .PHONY: build-web build-server: build-web diff --git a/web/declrations.d.ts b/web/declrations.d.ts index 84e2a8ac..f222bf22 100644 --- a/web/declrations.d.ts +++ b/web/declrations.d.ts @@ -23,3 +23,4 @@ declare module '*.scss'; declare const __STRIPE_PUBLIC_KEY__: string; declare const __ROOT_URL__: string; declare const __CDN_URL__: string; +declare const __VERSION__: string; diff --git a/web/scripts/build-prod.sh b/web/scripts/build-prod.sh index 8505e8bc..1ce40be7 100755 --- a/web/scripts/build-prod.sh +++ b/web/scripts/build-prod.sh @@ -15,4 +15,5 @@ ASSET_BASE_URL="$assetBaseUrl" \ ROOT_URL="$rootUrl" \ PUBLIC_PATH="$publicPath" \ COMPILED_PATH="$compiledPath" \ +VERSION="$VERSION" \ "$basePath"/web/scripts/build.sh diff --git a/web/scripts/build.sh b/web/scripts/build.sh index a44185ee..1b88ef3f 100755 --- a/web/scripts/build.sh +++ b/web/scripts/build.sh @@ -17,6 +17,7 @@ pushd "$basePath/web" OUTPUT_PATH="$COMPILED_PATH" \ ROOT_URL="$ROOT_URL" \ + VERSION="$VERSION" \ "$basePath"/web/node_modules/.bin/webpack\ --colors\ --display-error-details\ diff --git a/web/scripts/dev.sh b/web/scripts/dev.sh index 595bce88..e3755430 100755 --- a/web/scripts/dev.sh +++ b/web/scripts/dev.sh @@ -31,6 +31,7 @@ set +a PUBLIC_PATH="$appPath"/public \ COMPILED_PATH="$basePath/web/compiled" \ IS_TEST=true \ + VERSION="$VERSION" \ "$appPath"/scripts/webpack-dev.sh ) & devServerPID=$! diff --git a/web/scripts/webpack-dev.sh b/web/scripts/webpack-dev.sh index 602ff9ee..5b3332c6 100755 --- a/web/scripts/webpack-dev.sh +++ b/web/scripts/webpack-dev.sh @@ -19,6 +19,7 @@ appPath="$basePath"/web node "$appPath"/scripts/placeholder.js && ROOT_URL=$ROOT_URL \ + VERSION="$VERSION" \ "$appPath"/node_modules/.bin/webpack-dev-server\ --env.isTest="$IS_TEST"\ --config "$appPath"/webpack/dev.config.js diff --git a/web/src/components/Settings/About/index.tsx b/web/src/components/Settings/About/index.tsx new file mode 100644 index 00000000..a030fbf6 --- /dev/null +++ b/web/src/components/Settings/About/index.tsx @@ -0,0 +1,62 @@ +/* Copyright (C) 2019 Monomax Software Pty Ltd + * + * This file is part of Dnote. + * + * Dnote is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Dnote is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Dnote. If not, see . + */ + +import React, { useState } from 'react'; +import Helmet from 'react-helmet'; +import classnames from 'classnames'; + +import SettingRow from '../SettingRow'; +import styles from '../Settings.scss'; +import { useSelector } from '../../../store'; +import config from '../../../libs/config'; + +interface Props {} + +const About: React.FunctionComponent = () => { + const { user } = useSelector(state => { + return { + user: state.auth.user.data + }; + }); + + return ( +
+ + About + + +

About

+ +
+
+

Software

+ + + {user.pro && ( + sung@getdnote.com} + /> + )} +
+
+
+ ); +}; + +export default About; diff --git a/web/src/components/Settings/Billing/CancelPlanModal.tsx b/web/src/components/Settings/Billing/CancelPlanModal.tsx index 757028b6..e2489f8e 100644 --- a/web/src/components/Settings/Billing/CancelPlanModal.tsx +++ b/web/src/components/Settings/Billing/CancelPlanModal.tsx @@ -83,7 +83,7 @@ const CancelPlanModal: React.FunctionComponent = ({ + } + /> + ); +}; + +export default PaymentMethodRow; diff --git a/web/src/components/Settings/Billing/Placeholder.scss b/web/src/components/Settings/Billing/PaymentSection/Placeholder.scss similarity index 54% rename from web/src/components/Settings/Billing/Placeholder.scss rename to web/src/components/Settings/Billing/PaymentSection/Placeholder.scss index f7af5fc7..b9463285 100644 --- a/web/src/components/Settings/Billing/Placeholder.scss +++ b/web/src/components/Settings/Billing/PaymentSection/Placeholder.scss @@ -16,82 +16,34 @@ * along with Dnote. If not, see . */ -@import '../../App/rem'; -@import '../../App/font'; -@import '../../App/theme'; +@import '../../../App/rem'; +@import '../../../App/font'; +@import '../../../App/theme'; -.content1 { - position: relative; - padding: rem(48px) rem(12px); -} - -.content1-line1 { - width: rem(140px); - height: rem(16px); -} -.content1-line2 { - width: rem(240px); - height: rem(16px); - margin-top: rem(8px); -} -.content1-line3 { - width: rem(80px); - height: rem(16px); - margin-top: rem(8px); -} - -.content2 { +.content { display: flex; justify-content: space-between; flex-direction: column; position: relative; - padding: rem(8px) rem(12px); + padding: rem(16px) rem(12px); @include breakpoint(md) { flex-direction: row; } } -.content2-line1 { +.content-line1 { width: rem(120px); height: rem(16px); margin-top: rem(8px); } -.content2-line2 { +.content-line2 { width: rem(180px); height: rem(16px); margin-top: rem(8px); } -.content2-right { - display: flex; - align-items: center; -} - -.content3 { - display: flex; - justify-content: space-between; - flex-direction: column; - position: relative; - padding: rem(8px) rem(12px); - - @include breakpoint(md) { - flex-direction: row; - } -} -.content3-line1 { - width: rem(120px); - height: rem(16px); - margin-top: rem(8px); -} - -.content3-line2 { - width: rem(180px); - height: rem(16px); - margin-top: rem(8px); -} - -.content3-right { +.content-right { display: flex; align-items: center; } diff --git a/web/src/components/Settings/Billing/PaymentSection/Placeholder.tsx b/web/src/components/Settings/Billing/PaymentSection/Placeholder.tsx new file mode 100644 index 00000000..3ee5408b --- /dev/null +++ b/web/src/components/Settings/Billing/PaymentSection/Placeholder.tsx @@ -0,0 +1,51 @@ +/* Copyright (C) 2019 Monomax Software Pty Ltd + * + * This file is part of Dnote. + * + * Dnote is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Dnote is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Dnote. If not, see . + */ + +import React from 'react'; +import classnames from 'classnames'; + +import settingsStyles from '../../Settings.scss'; +import styles from './Placeholder.scss'; + +const Placeholder: React.FunctionComponent = () => { + return ( +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ ); +}; + +export default Placeholder; diff --git a/web/src/components/Settings/Billing/PaymentSection/index.tsx b/web/src/components/Settings/Billing/PaymentSection/index.tsx new file mode 100644 index 00000000..6eb83cad --- /dev/null +++ b/web/src/components/Settings/Billing/PaymentSection/index.tsx @@ -0,0 +1,56 @@ +/* Copyright (C) 2019 Monomax Software Pty Ltd + * + * This file is part of Dnote. + * + * Dnote is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Dnote is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Dnote. If not, see . + */ + +import React, { Fragment } from 'react'; +import classnames from 'classnames'; + +import PaymentMethodRow from './PaymentMethodRow'; +import settingsStyles from '../../Settings.scss'; +import { SourceData } from '../../../../store/auth/type'; +import Placeholder from './Placeholder'; +import styles from './Placeholder.scss'; + +interface Props { + source: SourceData; + setIsPaymentMethodModalOpen: (boolean) => void; + stripeLoaded: boolean; + isFetched: boolean; +} + +const PaymentSection: React.FunctionComponent = ({ + source, + setIsPaymentMethodModalOpen, + stripeLoaded, + isFetched +}) => { + if (!isFetched) { + return ; + } + + return ( + + + + ); +}; + +export default PaymentSection; diff --git a/web/src/components/Settings/Billing/PlanSection/CancelRow.tsx b/web/src/components/Settings/Billing/PlanSection/CancelRow.tsx new file mode 100644 index 00000000..f2bec159 --- /dev/null +++ b/web/src/components/Settings/Billing/PlanSection/CancelRow.tsx @@ -0,0 +1,49 @@ +/* Copyright (C) 2019 Monomax Software Pty Ltd + * + * This file is part of Dnote. + * + * Dnote is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Dnote is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Dnote. If not, see . + */ + +import React, { useState, useEffect } from 'react'; +import classnames from 'classnames'; + +import SettingRow from '../../SettingRow'; +import styles from '../../Settings.scss'; + +interface Props { + setIsPlanModalOpen: (bool) => void; +} + +const CancelRow: React.FunctionComponent = ({ setIsPlanModalOpen }) => { + return ( + { + setIsPlanModalOpen(true); + }} + > + Cancel plan + + } + /> + ); +}; + +export default CancelRow; diff --git a/web/src/components/Settings/Billing/PlanSection/Placeholder.scss b/web/src/components/Settings/Billing/PlanSection/Placeholder.scss new file mode 100644 index 00000000..1acd357b --- /dev/null +++ b/web/src/components/Settings/Billing/PlanSection/Placeholder.scss @@ -0,0 +1,41 @@ +/* Copyright (C) 2019 Monomax Software Pty Ltd + * + * This file is part of Dnote. + * + * Dnote is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Dnote is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Dnote. If not, see . + */ + +@import '../../../App/rem'; +@import '../../../App/font'; +@import '../../../App/theme'; + +.content1 { + position: relative; + padding: rem(48px) rem(12px); +} + +.content1-line1 { + width: rem(140px); + height: rem(16px); +} +.content1-line2 { + width: rem(240px); + height: rem(16px); + margin-top: rem(8px); +} +.content1-line3 { + width: rem(80px); + height: rem(16px); + margin-top: rem(8px); +} diff --git a/web/src/components/Settings/Billing/Placeholder.tsx b/web/src/components/Settings/Billing/PlanSection/Placeholder.tsx similarity index 71% rename from web/src/components/Settings/Billing/Placeholder.tsx rename to web/src/components/Settings/Billing/PlanSection/Placeholder.tsx index 78fb6b86..d61f1e71 100644 --- a/web/src/components/Settings/Billing/Placeholder.tsx +++ b/web/src/components/Settings/Billing/PlanSection/Placeholder.tsx @@ -19,7 +19,7 @@ import React from 'react'; import classnames from 'classnames'; -import settingsStyles from '../Settings.scss'; +import settingsStyles from '../../Settings.scss'; import styles from './Placeholder.scss'; const Placeholder: React.FunctionComponent = () => { @@ -28,10 +28,6 @@ const Placeholder: React.FunctionComponent = () => {
-
-   -
-
@@ -55,26 +51,6 @@ const Placeholder: React.FunctionComponent = () => {
- -
-
-   -
- -
-
-
-
- -
-
-
-
-
diff --git a/web/src/components/Settings/Billing/PlanRow.scss b/web/src/components/Settings/Billing/PlanSection/PlanRow.scss similarity index 92% rename from web/src/components/Settings/Billing/PlanRow.scss rename to web/src/components/Settings/Billing/PlanSection/PlanRow.scss index ee9799bf..1cd043b1 100644 --- a/web/src/components/Settings/Billing/PlanRow.scss +++ b/web/src/components/Settings/Billing/PlanSection/PlanRow.scss @@ -16,9 +16,9 @@ * along with Dnote. If not, see . */ -@import '../../App/rem'; -@import '../../App/font'; -@import '../../App/theme'; +@import '../../../App/rem'; +@import '../../../App/font'; +@import '../../../App/theme'; .wrapper { padding-top: rem(48px); diff --git a/web/src/components/Settings/Billing/PlanRow.tsx b/web/src/components/Settings/Billing/PlanSection/PlanRow.tsx similarity index 90% rename from web/src/components/Settings/Billing/PlanRow.tsx rename to web/src/components/Settings/Billing/PlanSection/PlanRow.tsx index c983e4f9..c4bf7733 100644 --- a/web/src/components/Settings/Billing/PlanRow.tsx +++ b/web/src/components/Settings/Billing/PlanSection/PlanRow.tsx @@ -21,11 +21,11 @@ import { Link } from 'react-router-dom'; import classnames from 'classnames'; import { getPlanLabel } from 'web/libs/subscription'; -import LogoIcon from '../../Icons/Logo'; -import { nanosecToMillisec } from 'web/helpers/time'; +import LogoIcon from '../../../Icons/Logo'; +import { SECOND } from 'web/helpers/time'; import formatDate from 'web/helpers/time/format'; import styles from './PlanRow.scss'; -import settingRowStyles from '../SettingRow.scss'; +import settingRowStyles from '../../SettingRow.scss'; function getPlanPeriodMessage(subscription: any): string { if (!subscription.id) { @@ -34,12 +34,12 @@ function getPlanPeriodMessage(subscription: any): string { const label = getPlanLabel(subscription); - const endDate = new Date(nanosecToMillisec(subscription.current_period_end)); + const endDate = new Date(subscription.current_period_end * SECOND); if (subscription.cancel_at_period_end) { return `Your ${label} plan will end on ${formatDate( endDate, - 'YYYY MMM Do' + '%YYYY %MMM %Do' )} and will not renew.`; } @@ -47,7 +47,7 @@ function getPlanPeriodMessage(subscription: any): string { renewDate.setDate(endDate.getDate() + 1); return `Your ${label} plan will renew on ${formatDate( renewDate, - 'YYYY MMM Do' + '%YYYY %MMM %Do' )}.`; } diff --git a/web/src/components/Settings/Billing/ReactivateRow.tsx b/web/src/components/Settings/Billing/PlanSection/ReactivateRow.tsx similarity index 92% rename from web/src/components/Settings/Billing/ReactivateRow.tsx rename to web/src/components/Settings/Billing/PlanSection/ReactivateRow.tsx index 59b3daa7..d3ea5297 100644 --- a/web/src/components/Settings/Billing/ReactivateRow.tsx +++ b/web/src/components/Settings/Billing/PlanSection/ReactivateRow.tsx @@ -20,10 +20,10 @@ import React, { useState } from 'react'; import classnames from 'classnames'; import services from 'web/libs/services'; -import { useDispatch } from '../../../store'; -import { getSubscription } from '../../../store/auth'; -import SettingRow from '../SettingRow'; -import styles from '../Settings.scss'; +import { useDispatch } from '../../../../store'; +import { getSubscription } from '../../../../store/auth'; +import SettingRow from '../../SettingRow'; +import styles from '../../Settings.scss'; interface Props { subscriptionId: string; diff --git a/web/src/components/Settings/Billing/PlanSection/index.tsx b/web/src/components/Settings/Billing/PlanSection/index.tsx new file mode 100644 index 00000000..535cfd32 --- /dev/null +++ b/web/src/components/Settings/Billing/PlanSection/index.tsx @@ -0,0 +1,67 @@ +/* Copyright (C) 2019 Monomax Software Pty Ltd + * + * This file is part of Dnote. + * + * Dnote is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Dnote is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Dnote. If not, see . + */ + +import React, { Fragment } from 'react'; +import classnames from 'classnames'; + +import PlanRow from './PlanRow'; +import CancelRow from './CancelRow'; +import ReactivateRow from './ReactivateRow'; +import settingsStyles from '../../Settings.scss'; +import { SubscriptionData } from '../../../../store/auth/type'; +import Placeholder from './Placeholder'; +import styles from './Placeholder.scss'; + +interface Props { + subscription: SubscriptionData; + setIsPlanModalOpen: (boolean) => void; + setSuccessMsg: (string) => void; + setFailureMsg: (string) => void; + isFetched: boolean; +} + +const PlanSection: React.FunctionComponent = ({ + subscription, + isFetched, + setIsPlanModalOpen, + setSuccessMsg, + setFailureMsg +}) => { + if (!isFetched) { + return ; + } + + return ( + + + + {subscription.id && !subscription.cancel_at_period_end && ( + + )} + {subscription.id && subscription.cancel_at_period_end && ( + + )} + + ); +}; + +export default PlanSection; diff --git a/web/src/components/Settings/Billing/index.tsx b/web/src/components/Settings/Billing/index.tsx index e246b0a2..43950a26 100644 --- a/web/src/components/Settings/Billing/index.tsx +++ b/web/src/components/Settings/Billing/index.tsx @@ -32,143 +32,10 @@ import { clearSource } from '../../../store/auth'; import SettingRow from '../SettingRow'; -import ReactivateRow from './ReactivateRow'; -import PlanRow from './PlanRow'; -import Placeholder from './Placeholder'; +import PlanSection from './PlanSection'; +import PaymentSection from './PaymentSection'; import styles from '../Settings.scss'; -function CancelRow({ setIsPlanModalOpen }) { - return ( - { - setIsPlanModalOpen(true); - }} - > - Cancel plan - - } - /> - ); -} - -function PaymentMethodRow({ - stripeLoaded, - source, - setIsPaymentMethodModalOpen -}) { - let value; - if (source.brand) { - value = `${source.brand} ending in ${source.last4}. expiry ${source.exp_month}/${source.exp_year}`; - } else { - value = 'No payment method'; - } - - return ( - { - setIsPaymentMethodModalOpen(true); - }} - disabled={!stripeLoaded} - > - Update - - } - /> - ); -} - -interface ContentProps { - subscription: any; - source: any; - setIsPlanModalOpen: (boolean) => void; - setIsPaymentMethodModalOpen: (boolean) => void; - successMsg: string; - failureMsg: string; - setSuccessMsg: (string) => void; - setFailureMsg: (string) => void; - stripeLoaded: boolean; -} - -const Content: React.FunctionComponent = ({ - subscription, - source, - setIsPlanModalOpen, - setIsPaymentMethodModalOpen, - successMsg, - failureMsg, - setSuccessMsg, - setFailureMsg, - stripeLoaded -}) => { - return ( -
- { - setSuccessMsg(''); - }} - > - {successMsg} - - { - setFailureMsg(''); - }} - > - {failureMsg} - - -
-
-

Plan

- - - - {subscription.id && !subscription.cancel_at_period_end && ( - - )} - {subscription.id && subscription.cancel_at_period_end && ( - - )} -
- -
-

Payment

- - -
-
-
- ); -}; - const Billing: React.FunctionComponent = () => { const [isPlanModalOpen, setIsPlanModalOpen] = useState(false); const [isPaymentMethodModalOpen, setIsPaymentMethodModalOpen] = useState( @@ -239,21 +106,53 @@ const Billing: React.FunctionComponent = () => { {stripeLoadError} - {!subscriptionData.isFetched || !sourceData.isFetched ? ( - - ) : ( - - )} +
+ { + setSuccessMsg(''); + }} + > + {successMsg} + + { + setFailureMsg(''); + }} + > + {failureMsg} + + +
+
+

Plan

+ + +
+ +
+

Payment

+ + +
+
+
{ ); }; -// function mapStateToProps(state) { -// return { -// subscriptionData: state.auth.subscription, -// sourceData: state.auth.source -// }; -// } - -// const mapDispatchToProps = { -// doGetSubscription: getSubscription, -// doClearSubscription: clearSubscription, -// doGetSource: getSource, -// doClearSource: clearSource -// }; - export default Billing; diff --git a/web/src/components/Settings/SettingRow.scss b/web/src/components/Settings/SettingRow.scss index 82f3614b..049af78d 100644 --- a/web/src/components/Settings/SettingRow.scss +++ b/web/src/components/Settings/SettingRow.scss @@ -62,6 +62,7 @@ .right { display: flex; flex-direction: column; + word-break: break-all; @include breakpoint(md) { flex-direction: row; diff --git a/web/src/components/Settings/SettingRow.tsx b/web/src/components/Settings/SettingRow.tsx index 405e589a..7625b576 100644 --- a/web/src/components/Settings/SettingRow.tsx +++ b/web/src/components/Settings/SettingRow.tsx @@ -23,10 +23,10 @@ import styles from './SettingRow.scss'; interface Props { name: string; - actionContent: React.ReactNode; + actionContent?: React.ReactNode; id?: string; desc?: string; - value?: string; + value?: React.ReactNode; } const SettingRow: React.FunctionComponent = ({ @@ -45,7 +45,8 @@ const SettingRow: React.FunctionComponent = ({
{value} -
{actionContent}
+ + {actionContent &&
{actionContent}
}
); diff --git a/web/src/components/Settings/Sidebar.tsx b/web/src/components/Settings/Sidebar.tsx index d270bcad..1b7f948d 100644 --- a/web/src/components/Settings/Sidebar.tsx +++ b/web/src/components/Settings/Sidebar.tsx @@ -47,6 +47,15 @@ const Sidebar: React.FunctionComponent = () => { Billing +
  • + + About + +
  • ); diff --git a/web/src/components/Settings/index.tsx b/web/src/components/Settings/index.tsx index d7a91470..c5bc94df 100644 --- a/web/src/components/Settings/index.tsx +++ b/web/src/components/Settings/index.tsx @@ -24,6 +24,7 @@ import classnames from 'classnames'; import { SettingSections } from 'web/libs/paths'; import Account from './Account'; import Sidebar from './Sidebar'; +import About from './About'; import Billing from './Billing'; import styles from './Settings.scss'; @@ -34,6 +35,9 @@ function renderContent(section: string): React.ReactNode { if (section === SettingSections.billing) { return ; } + if (section === SettingSections.about) { + return ; + } return
    Not found
    ; } diff --git a/web/src/libs/config.ts b/web/src/libs/config.ts index 6678ce79..74ed5623 100644 --- a/web/src/libs/config.ts +++ b/web/src/libs/config.ts @@ -17,5 +17,6 @@ */ export default { - cdnUrl: __CDN_URL__ + cdnUrl: __CDN_URL__, + version: __VERSION__ }; diff --git a/web/src/libs/paths.ts b/web/src/libs/paths.ts index 656bc59e..82fc0479 100644 --- a/web/src/libs/paths.ts +++ b/web/src/libs/paths.ts @@ -210,8 +210,8 @@ export function getPasswordResetConfirmPath(searchObj = {}): Location { export enum SettingSections { account = 'account', - spacedRepeition = 'spaced-repetition', - billing = 'billing' + billing = 'billing', + about = 'about' } export function getSettingsPath(section: SettingSections) { diff --git a/web/webpack/plugins.js b/web/webpack/plugins.js index d8f03212..fc46e5e0 100644 --- a/web/webpack/plugins.js +++ b/web/webpack/plugins.js @@ -31,11 +31,13 @@ module.exports = ({ production = false, test = false } = {}) => { } const cdnUrl = 'https://cdn.getdnote.com'; + const version = process.env.VERSION; const compileTimeConstantForMinification = { __ROOT_URL__: JSON.stringify(rootUrl), __STRIPE_PUBLIC_KEY__: JSON.stringify(stripePublicKey), - __CDN_URL__: JSON.stringify(cdnUrl) + __CDN_URL__: JSON.stringify(cdnUrl), + __VERSION__: JSON.stringify(version) }; if (!production) {