From 28dab13fb19631bcf8946d8fc40306b086fff676 Mon Sep 17 00:00:00 2001 From: Antonella Sgarlatta Date: Tue, 7 Sep 2021 12:04:25 -0300 Subject: [PATCH] refactor: use mobx for state and separate files for components --- .../preferences/panes/AccountPreferences.tsx | 4 +- .../panes/account/Subscription.tsx | 222 ------------------ .../preferences/panes/account/index.ts | 2 +- .../subscription/ActiveSubscription.tsx | 49 ++++ .../subscription/CancelledSubscription.tsx | 50 ++++ .../account/subscription/NoSubscription.tsx | 23 ++ .../account/subscription/Subscription.tsx | 92 ++++++++ .../subscription/SubscriptionWrapper.tsx | 20 ++ .../subscription/subscription_state.tsx | 51 ++++ 9 files changed, 288 insertions(+), 225 deletions(-) delete mode 100644 app/assets/javascripts/preferences/panes/account/Subscription.tsx create mode 100644 app/assets/javascripts/preferences/panes/account/subscription/ActiveSubscription.tsx create mode 100644 app/assets/javascripts/preferences/panes/account/subscription/CancelledSubscription.tsx create mode 100644 app/assets/javascripts/preferences/panes/account/subscription/NoSubscription.tsx create mode 100644 app/assets/javascripts/preferences/panes/account/subscription/Subscription.tsx create mode 100644 app/assets/javascripts/preferences/panes/account/subscription/SubscriptionWrapper.tsx create mode 100644 app/assets/javascripts/preferences/panes/account/subscription/subscription_state.tsx diff --git a/app/assets/javascripts/preferences/panes/AccountPreferences.tsx b/app/assets/javascripts/preferences/panes/AccountPreferences.tsx index 8dd126cba..4d74e7a89 100644 --- a/app/assets/javascripts/preferences/panes/AccountPreferences.tsx +++ b/app/assets/javascripts/preferences/panes/AccountPreferences.tsx @@ -1,4 +1,4 @@ -import { Sync, Subscription } from '@/preferences/panes/account'; +import { Sync, SubscriptionWrapper } from '@/preferences/panes/account'; import { PreferencesPane } from '@/preferences/components'; import { observer } from 'mobx-react-lite'; import { WebApplication } from '@/ui_models/application'; @@ -7,7 +7,7 @@ export const AccountPreferences = observer(({application}: {application: WebAppl return ( - + ); }); diff --git a/app/assets/javascripts/preferences/panes/account/Subscription.tsx b/app/assets/javascripts/preferences/panes/account/Subscription.tsx deleted file mode 100644 index 712964a17..000000000 --- a/app/assets/javascripts/preferences/panes/account/Subscription.tsx +++ /dev/null @@ -1,222 +0,0 @@ -import { - PreferencesGroup, - PreferencesSegment, - Text, - Title, -} from '@/preferences/components'; -import { Button } from '@/components/Button'; -import { observer } from '@node_modules/mobx-react-lite'; -import { WebApplication } from '@/ui_models/application'; -import { useEffect, useState } from 'preact/hooks'; -import { - GetSubscriptionResponse, - GetSubscriptionsResponse, -} from '@standardnotes/snjs/dist/@types/services/api/responses'; - -type Props = { - application: WebApplication; -}; - -type Subscription = { - planName: string; - cancelled: boolean; - endsAt: number; -}; - -type AvailableSubscriptions = { - [key: string]: { - name: string; - }; -}; - -type SubscriptionInformationProps = { - subscription?: Subscription; - availableSubscriptions: AvailableSubscriptions; -}; - -type ValidSubscriptionProps = { - subscription: Subscription; - availableSubscriptions: AvailableSubscriptions; -}; - -const NoSubscription = () => ( - <> - You don't have a Standard Notes subscription yet. -
-
- -); - -const ActiveSubscription = ({ - subscription, - availableSubscriptions, -}: ValidSubscriptionProps) => ( - <> - - Your{' '} - - Standard Notes {availableSubscriptions[subscription.planName]} - {' '} - subscription will be{' '} - - renewed on {new Date(subscription.endsAt).toLocaleString()} - - . - -
-
- -); - -const CancelledSubscription = ({ - subscription, - availableSubscriptions, -}: ValidSubscriptionProps) => ( - <> - - Your{' '} - - Standard Notes {availableSubscriptions[subscription.planName]} - {' '} - subscription has been{' '} - - canceled but will remain valid until{' '} - {new Date(subscription.endsAt).toLocaleString()} - - . You may resubscribe below if you wish. - -
-
- -); - -const SubscriptionInformation = ({ - subscription, - availableSubscriptions, -}: SubscriptionInformationProps) => { - const now = new Date().getTime(); - if (subscription && subscription.endsAt > now) { - return subscription.cancelled ? ( - - ) : ( - - ); - } - return ; -}; - -const Subscription = observer(({ application }: Props) => { - const [subscription, setSubscription] = - useState(undefined); - const [availableSubscriptions, setAvailableSubscriptions] = - useState({}); - const [error, setError] = useState(false); - - useEffect(() => { - const getSubscriptions = async () => { - try { - const result = await application.getSubscriptions(); - if (result.data) { - const data = (result as GetSubscriptionsResponse).data; - setAvailableSubscriptions(data!); - } else { - setError(true); - } - } catch (e) { - setError(true); - } - }; - const getSubscription = async () => { - try { - const result = await application.getUserSubscription(); - if (!result.error && result.data) { - const data = (result as GetSubscriptionResponse).data; - const subscription = data!.subscription; - setSubscription(subscription); - } else { - setError(true); - } - } catch (e) { - setError(true); - } - }; - getSubscriptions(); - getSubscription(); - }, [application]); - - return ( - - -
-
- Subscription - {error ? ( - 'No subscription information available.' - ) : ( - - )} -
-
-
-
- ); -}); - -export default Subscription; diff --git a/app/assets/javascripts/preferences/panes/account/index.ts b/app/assets/javascripts/preferences/panes/account/index.ts index d30c31420..063947150 100644 --- a/app/assets/javascripts/preferences/panes/account/index.ts +++ b/app/assets/javascripts/preferences/panes/account/index.ts @@ -1,2 +1,2 @@ export { default as Sync } from './Sync'; -export { default as Subscription } from './Subscription'; +export { SubscriptionWrapper } from './subscription/SubscriptionWrapper'; diff --git a/app/assets/javascripts/preferences/panes/account/subscription/ActiveSubscription.tsx b/app/assets/javascripts/preferences/panes/account/subscription/ActiveSubscription.tsx new file mode 100644 index 000000000..eb5d984ad --- /dev/null +++ b/app/assets/javascripts/preferences/panes/account/subscription/ActiveSubscription.tsx @@ -0,0 +1,49 @@ +import { observer } from 'mobx-react-lite'; +import { SubscriptionState } from './subscription_state'; +import { Text } from '@/preferences/components'; +import { Button } from '@/components/Button'; + +type Props = { + subscriptionState: SubscriptionState; +}; + +export const ActiveSubscription = observer( + ({ subscriptionState }: Props) => { + const { userSubscription, userSubscriptionName } = subscriptionState; + return ( + <> + + Your{' '} + + Standard Notes{userSubscriptionName ? " " : ""}{userSubscriptionName} + {' '} + subscription will be{' '} + + renewed on {new Date(userSubscription!.endsAt).toLocaleString()} + + . + +
+
+ + ); + } +); diff --git a/app/assets/javascripts/preferences/panes/account/subscription/CancelledSubscription.tsx b/app/assets/javascripts/preferences/panes/account/subscription/CancelledSubscription.tsx new file mode 100644 index 000000000..84cf6639c --- /dev/null +++ b/app/assets/javascripts/preferences/panes/account/subscription/CancelledSubscription.tsx @@ -0,0 +1,50 @@ +import { observer } from 'mobx-react-lite'; +import { SubscriptionState } from './subscription_state'; +import { Text } from '@/preferences/components'; +import { Button } from '@/components/Button'; + +type Props = { + subscriptionState: SubscriptionState; +}; + +export const CancelledSubscription = observer( + ({ subscriptionState }: Props) => { + const { userSubscription, userSubscriptionName } = subscriptionState; + return ( + <> + + Your{' '} + + Standard NotesStandard Notes{userSubscriptionName ? " " : ""}{userSubscriptionName} + {' '} + subscription has been{' '} + + canceled but will remain valid until{' '} + {new Date(userSubscription!.endsAt).toLocaleString()} + + . You may resubscribe below if you wish. + +
+
+ + ); + } +); diff --git a/app/assets/javascripts/preferences/panes/account/subscription/NoSubscription.tsx b/app/assets/javascripts/preferences/panes/account/subscription/NoSubscription.tsx new file mode 100644 index 000000000..5042ea992 --- /dev/null +++ b/app/assets/javascripts/preferences/panes/account/subscription/NoSubscription.tsx @@ -0,0 +1,23 @@ +import { FunctionalComponent } from "preact"; +import { Text } from '@/preferences/components'; +import { Button } from '@/components/Button'; + +export const NoSubscription: FunctionalComponent = () => ( + <> + You don't have a Standard Notes subscription yet. +
+
+ +); diff --git a/app/assets/javascripts/preferences/panes/account/subscription/Subscription.tsx b/app/assets/javascripts/preferences/panes/account/subscription/Subscription.tsx new file mode 100644 index 000000000..3ced9309e --- /dev/null +++ b/app/assets/javascripts/preferences/panes/account/subscription/Subscription.tsx @@ -0,0 +1,92 @@ +import { + PreferencesGroup, + PreferencesSegment, + Title, +} from '@/preferences/components'; +import { observer } from '@node_modules/mobx-react-lite'; +import { WebApplication } from '@/ui_models/application'; +import { useEffect, useState } from 'preact/hooks'; +import { + GetSubscriptionResponse, + GetSubscriptionsResponse, +} from '@standardnotes/snjs/dist/@types/services/api/responses'; +import { SubscriptionState } from './subscription_state'; +import { CancelledSubscription } from './CancelledSubscription'; +import { ActiveSubscription } from './ActiveSubscription'; +import { NoSubscription } from './NoSubscription'; + +type Props = { + application: WebApplication; + subscriptionState: SubscriptionState; +}; + +type SubscriptionInformationProps = { + subscriptionState: SubscriptionState; +}; + +const SubscriptionInformation = ({ + subscriptionState, +}: SubscriptionInformationProps) => { + const now = new Date().getTime(); + const { userSubscription } = subscriptionState; + + if (userSubscription && userSubscription.endsAt > now) { + return userSubscription.cancelled ? ( + + ) : ( + + ); + } + return ; +}; + +export const Subscription = observer(({ application, subscriptionState }: Props) => { + const [error, setError] = useState(false); + + useEffect(() => { + const getSubscriptions = async () => { + try { + const result = await application.getSubscriptions(); + if (result.data) { + const data = (result as GetSubscriptionsResponse).data; + subscriptionState.setAvailableSubscriptions(data!); + } + } catch (e) { + // Error in this call will only prevent the plan name from showing + } + }; + const getSubscription = async () => { + try { + const result = await application.getUserSubscription(); + if (!result.error && result.data) { + const data = (result as GetSubscriptionResponse).data; + const subscription = data!.subscription; + subscriptionState.setUserSubscription(subscription); + } else { + setError(true); + } + } catch (e) { + setError(true); + } + }; + getSubscriptions(); + getSubscription(); + }, [application, subscriptionState]); + + return ( + + +
+
+ Subscription + {error ? ( + 'No subscription information available.' + ) : ( + + )} +
+
+
+
+ ); +}); diff --git a/app/assets/javascripts/preferences/panes/account/subscription/SubscriptionWrapper.tsx b/app/assets/javascripts/preferences/panes/account/subscription/SubscriptionWrapper.tsx new file mode 100644 index 000000000..9a1c4033f --- /dev/null +++ b/app/assets/javascripts/preferences/panes/account/subscription/SubscriptionWrapper.tsx @@ -0,0 +1,20 @@ +import { WebApplication } from '@/ui_models/application'; +import { FunctionalComponent } from 'preact'; +import { Subscription } from './Subscription'; +import { SubscriptionState } from './subscription_state'; + +type Props = { + application: WebApplication; +}; + +export const SubscriptionWrapper: FunctionalComponent = ({ + application, +}) => { + const subscriptionState = new SubscriptionState(); + return ( + + ); +}; diff --git a/app/assets/javascripts/preferences/panes/account/subscription/subscription_state.tsx b/app/assets/javascripts/preferences/panes/account/subscription/subscription_state.tsx new file mode 100644 index 000000000..aaa2bab72 --- /dev/null +++ b/app/assets/javascripts/preferences/panes/account/subscription/subscription_state.tsx @@ -0,0 +1,51 @@ +import { action, computed, makeObservable, observable } from 'mobx'; + +type Subscription = { + planName: string; + cancelled: boolean; + endsAt: number; +}; + +type AvailableSubscriptions = { + [key: string]: { + name: string; + }; +}; + +export class SubscriptionState { + userSubscription: Subscription | undefined; + availableSubscriptions: AvailableSubscriptions | undefined; + + constructor() { + makeObservable(this, { + userSubscription: observable, + availableSubscriptions: observable, + + userSubscriptionName: computed, + + setUserSubscription: action, + setAvailableSubscriptions: action, + }); + } + + get userSubscriptionName(): string { + if ( + this.availableSubscriptions && + this.userSubscription && + this.availableSubscriptions[this.userSubscription.planName] + ) { + return this.availableSubscriptions[this.userSubscription.planName].name; + } + return ''; + } + + public setUserSubscription(subscription: Subscription): void { + this.userSubscription = subscription; + } + + public setAvailableSubscriptions( + subscriptions: AvailableSubscriptions + ): void { + this.availableSubscriptions = subscriptions; + } +}