Skip to content

Commit

Permalink
feat: display warning banner when using the app with no account
Browse files Browse the repository at this point in the history
  • Loading branch information
arielsvg committed Feb 2, 2021
1 parent 94473da commit c084268
Show file tree
Hide file tree
Showing 26 changed files with 697 additions and 185 deletions.
38 changes: 0 additions & 38 deletions app/assets/fonts/ionicons.svg

This file was deleted.

3 changes: 3 additions & 0 deletions app/assets/icons/ic_close.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions app/assets/javascripts/@types/modules.ts
@@ -0,0 +1,3 @@
declare module '*.svg' {
export default function SvgComponent(props: React.SVGProps<SVGSVGElement>): JSX.Element;
}
6 changes: 4 additions & 2 deletions app/assets/javascripts/app.ts
Expand Up @@ -55,7 +55,8 @@ import { BrowserBridge } from './services/browserBridge';
import { startErrorReporting } from './services/errorReporting';
import { StartApplication } from './startApplication';
import { Bridge } from './services/bridge';
import { SessionsModalDirective } from './directives/views/sessionsModal';
import { SessionsModalDirective } from './components/SessionsModal';
import { NoAccountWarningDirective } from './components/NoAccountWarning';


function reloadHiddenFirefoxTab(): boolean {
Expand Down Expand Up @@ -141,7 +142,8 @@ const startApplication: StartApplication = async function startApplication(
.directive('revisionPreviewModal', () => new RevisionPreviewModal())
.directive('historyMenu', () => new HistoryMenu())
.directive('syncResolutionMenu', () => new SyncResolutionMenu())
.directive('sessionsModal', SessionsModalDirective);
.directive('sessionsModal', SessionsModalDirective)
.directive('noAccountWarning', NoAccountWarningDirective);

// Filters
angular.module('app').filter('trusted', ['$sce', trusted]);
Expand Down
46 changes: 46 additions & 0 deletions app/assets/javascripts/components/NoAccountWarning.tsx
@@ -0,0 +1,46 @@
import { WebApplication } from '@/ui_models/application';
import { toDirective, useAutorunValue } from './utils';
import Close from '../../icons/ic_close.svg';
import { AppState } from '@/ui_models/app_state';

function NoAccountWarning({
application,
appState,
}: {
application: WebApplication;
appState: AppState;
}) {
const canShow = useAutorunValue(() => appState.noAccountWarning.show);
if (!canShow || application.hasAccount()) {
return null;
}
return (
<div className="mt-5 p-5 rounded-md shadow-sm grid grid-template-cols-1fr">
<h1 className="sk-h3 m-0 font-semibold">Data not backed up</h1>
<p className="m-0 mt-1 col-start-1 col-end-3">
Sign in or register to back up your notes
</p>
<button
className="sn-btn mt-3 col-start-1 col-end-3 justify-self-start"
onClick={(event) => {
event.stopPropagation();
appState.accountMenu.setShow(true);
}}
>
Open Account menu
</button>
<button
onClick={() => {
appState.noAccountWarning.hide();
}}
title="Ignore"
label="Ignore"
className="border-0 p-0 bg-transparent cursor-pointer rounded-md col-start-2 row-start-1"
>
<Close className="fill-neutral hover:fill-info" />
</button>
</div>
);
}

export const NoAccountWarningDirective = toDirective(NoAccountWarning);
@@ -1,14 +1,12 @@
import { AppState } from '@/ui_models/app_state';
import { PureViewCtrl } from '@/views';
import {
SNApplication,
RemoteSession,
SessionStrings,
UuidString,
isNullOrUndefined,
RemoteSession,
} from '@standardnotes/snjs';
import { autorun, IAutorunOptions, IReactionPublic } from 'mobx';
import { render, FunctionComponent } from 'preact';
import { FunctionComponent } from 'preact';
import { useState, useEffect, useRef, useMemo } from 'preact/hooks';
import { Dialog } from '@reach/dialog';
import { Alert } from '@reach/alert';
Expand All @@ -17,13 +15,8 @@ import {
AlertDialogDescription,
AlertDialogLabel,
} from '@reach/alert-dialog';

function useAutorun(
view: (r: IReactionPublic) => unknown,
opts?: IAutorunOptions
) {
useEffect(() => autorun(view, opts), [view, opts]);
}
import { toDirective, useAutorun } from './utils';
import { WebApplication } from '@/ui_models/application';

type Session = RemoteSession & {
revoking?: true;
Expand Down Expand Up @@ -250,7 +243,7 @@ const SessionsModal: FunctionComponent<{

const Sessions: FunctionComponent<{
appState: AppState;
application: SNApplication;
application: WebApplication;
}> = ({ appState, application }) => {
const [showModal, setShowModal] = useState(false);
useAutorun(() => setShowModal(appState.isSessionsModalVisible));
Expand All @@ -262,27 +255,4 @@ const Sessions: FunctionComponent<{
}
};

class SessionsModalCtrl extends PureViewCtrl<unknown, unknown> {
/* @ngInject */
constructor(private $element: JQLite, $timeout: ng.ITimeoutService) {
super($timeout);
this.$element = $element;
}
$onChanges() {
render(
<Sessions appState={this.appState} application={this.application} />,
this.$element[0]
);
}
}

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function SessionsModalDirective() {
return {
controller: SessionsModalCtrl,
bindToController: true,
scope: {
application: '=',
},
};
}
export const SessionsModalDirective = toDirective(Sessions);
56 changes: 56 additions & 0 deletions app/assets/javascripts/components/utils.ts
@@ -0,0 +1,56 @@
import { WebApplication } from '@/ui_models/application';
import { AppState } from '@/ui_models/app_state';
import { autorun, IAutorunOptions, IReactionPublic } from 'mobx';
import { FunctionComponent, h, render } from 'preact';
import { useEffect } from 'preact/hooks';
import { useState } from 'react';

export function useAutorunValue<T>(query: () => T): T {
const [value, setValue] = useState(query);
useAutorun(() => {
setValue(query());
});
return value;
}

export function useAutorun(
view: (r: IReactionPublic) => unknown,
opts?: IAutorunOptions
): void {
useEffect(() => autorun(view, opts), [view, opts]);
}

export function toDirective(
component: FunctionComponent<{
application: WebApplication;
appState: AppState;
}>
) {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
return function () {
return {
controller: [
'$element',
'$scope',
// eslint-disable-next-line @typescript-eslint/no-explicit-any
($element: JQLite, $scope: any) => {
return {
$onChanges() {
render(
h(component, {
application: $scope.application,
appState: $scope.appState,
}),
$element[0]
);
},
};
},
],
scope: {
application: '=',
appState: '=',
},
};
};
}
2 changes: 1 addition & 1 deletion app/assets/javascripts/services/desktopManager.ts
Expand Up @@ -75,7 +75,7 @@ export class DesktopManager extends ApplicationService {

getExtServerHost() {
console.assert(
this.bridge.extensionsServerHost,
!!this.bridge.extensionsServerHost,
'extServerHost is null'
);
return this.bridge.extensionsServerHost;
Expand Down
4 changes: 4 additions & 0 deletions app/assets/javascripts/services/localStorage.ts
@@ -1,11 +1,15 @@
export enum StorageKey {
DisableErrorReporting = 'DisableErrorReporting',
AnonymousUserId = 'AnonymousUserId',
ShowBetaWarning = 'ShowBetaWarning',
ShowNoAccountWarning = 'ShowNoAccountWarning',
}

export type StorageValue = {
[StorageKey.DisableErrorReporting]: boolean;
[StorageKey.AnonymousUserId]: string;
[StorageKey.ShowBetaWarning]: boolean;
[StorageKey.ShowNoAccountWarning]: boolean;
}

export const storage = {
Expand Down
3 changes: 2 additions & 1 deletion app/assets/javascripts/tsconfig.json
Expand Up @@ -6,14 +6,15 @@
"allowJs": true,
"noEmit": true,
"strict": true,
"isolatedModules": true,
"isolatedModules": false,
"esModuleInterop": true,
"declaration": true,
"newLine": "lf",
"declarationDir": "../../../dist/@types",
"baseUrl": ".",
"jsx": "react-jsx",
"jsxImportSource": "preact",
"typeRoots": ["./@types"],
"paths": {
"%/*": ["../templates/*"],
"@/*": ["./*"],
Expand Down

0 comments on commit c084268

Please sign in to comment.