Add account creation
parent
c89ec94b17
commit
ef4b9cf8d9
|
@ -291,8 +291,6 @@ PODS:
|
||||||
- React-jsi (= 0.68.2)
|
- React-jsi (= 0.68.2)
|
||||||
- React-logger (= 0.68.2)
|
- React-logger (= 0.68.2)
|
||||||
- React-perflogger (= 0.68.2)
|
- React-perflogger (= 0.68.2)
|
||||||
- rn-fetch-blob (0.12.0):
|
|
||||||
- React-Core
|
|
||||||
- RNCAsyncStorage (1.17.10):
|
- RNCAsyncStorage (1.17.10):
|
||||||
- React-Core
|
- React-Core
|
||||||
- RNCClipboard (1.11.1):
|
- RNCClipboard (1.11.1):
|
||||||
|
@ -370,7 +368,6 @@ DEPENDENCIES:
|
||||||
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
|
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
|
||||||
- React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`)
|
- React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`)
|
||||||
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
|
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
|
||||||
- rn-fetch-blob (from `../node_modules/rn-fetch-blob`)
|
|
||||||
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
|
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
|
||||||
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
|
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
|
||||||
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
|
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
|
||||||
|
@ -449,8 +446,6 @@ EXTERNAL SOURCES:
|
||||||
:path: "../node_modules/react-native/ReactCommon/runtimeexecutor"
|
:path: "../node_modules/react-native/ReactCommon/runtimeexecutor"
|
||||||
ReactCommon:
|
ReactCommon:
|
||||||
:path: "../node_modules/react-native/ReactCommon"
|
:path: "../node_modules/react-native/ReactCommon"
|
||||||
rn-fetch-blob:
|
|
||||||
:path: "../node_modules/rn-fetch-blob"
|
|
||||||
RNCAsyncStorage:
|
RNCAsyncStorage:
|
||||||
:path: "../node_modules/@react-native-async-storage/async-storage"
|
:path: "../node_modules/@react-native-async-storage/async-storage"
|
||||||
RNCClipboard:
|
RNCClipboard:
|
||||||
|
@ -502,7 +497,6 @@ SPEC CHECKSUMS:
|
||||||
React-RCTVibration: 79040b92bfa9c3c2d2cb4f57e981164ec7ab9374
|
React-RCTVibration: 79040b92bfa9c3c2d2cb4f57e981164ec7ab9374
|
||||||
React-runtimeexecutor: b960b687d2dfef0d3761fbb187e01812ebab8b23
|
React-runtimeexecutor: b960b687d2dfef0d3761fbb187e01812ebab8b23
|
||||||
ReactCommon: 095366164a276d91ea704ce53cb03825c487a3f2
|
ReactCommon: 095366164a276d91ea704ce53cb03825c487a3f2
|
||||||
rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba
|
|
||||||
RNCAsyncStorage: 0c357f3156fcb16c8589ede67cc036330b6698ca
|
RNCAsyncStorage: 0c357f3156fcb16c8589ede67cc036330b6698ca
|
||||||
RNCClipboard: 2834e1c4af68697089cdd455ee4a4cdd198fa7dd
|
RNCClipboard: 2834e1c4af68697089cdd455ee4a4cdd198fa7dd
|
||||||
RNGestureHandler: 28ad20bf02257791f7f137b31beef34b9549f54b
|
RNGestureHandler: 28ad20bf02257791f7f137b31beef34b9549f54b
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
"@react-native-clipboard/clipboard": "^1.10.0",
|
"@react-native-clipboard/clipboard": "^1.10.0",
|
||||||
"@zxing/text-encoding": "^0.9.0",
|
"@zxing/text-encoding": "^0.9.0",
|
||||||
"base64-js": "^1.5.1",
|
"base64-js": "^1.5.1",
|
||||||
|
"email-validator": "^2.0.4",
|
||||||
"lodash.omit": "^4.5.0",
|
"lodash.omit": "^4.5.0",
|
||||||
"mobx": "^6.6.1",
|
"mobx": "^6.6.1",
|
||||||
"mobx-react-lite": "^3.4.0",
|
"mobx-react-lite": "^3.4.0",
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import {makeAutoObservable} from 'mobx'
|
import {makeAutoObservable} from 'mobx'
|
||||||
import AdxApi from '../../third-party/api'
|
import AdxApi from '../../third-party/api'
|
||||||
|
import type * as GetAccountsConfig from '../../third-party/api/src/types/todo/adx/getAccountsConfig'
|
||||||
import {isObj, hasProp} from '../lib/type-guards'
|
import {isObj, hasProp} from '../lib/type-guards'
|
||||||
import {RootStoreModel} from './root-store'
|
import {RootStoreModel} from './root-store'
|
||||||
|
|
||||||
|
export type ServiceDescription = GetAccountsConfig.OutputSchema
|
||||||
|
|
||||||
interface SessionData {
|
interface SessionData {
|
||||||
service: string
|
service: string
|
||||||
token: string
|
token: string
|
||||||
|
@ -10,8 +13,17 @@ interface SessionData {
|
||||||
userdid: string
|
userdid: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum OnboardingStage {
|
||||||
|
Init = 'init',
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OnboardingState {
|
||||||
|
stage: OnboardingStage
|
||||||
|
}
|
||||||
|
|
||||||
export class SessionModel {
|
export class SessionModel {
|
||||||
data: SessionData | null = null
|
data: SessionData | null = null
|
||||||
|
onboardingState: OnboardingState | null = null
|
||||||
|
|
||||||
constructor(public rootStore: RootStoreModel) {
|
constructor(public rootStore: RootStoreModel) {
|
||||||
makeAutoObservable(this, {
|
makeAutoObservable(this, {
|
||||||
|
@ -26,31 +38,51 @@ export class SessionModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize(): unknown {
|
serialize(): unknown {
|
||||||
return this.data
|
return {
|
||||||
|
data: this.data,
|
||||||
|
onboardingState: this.onboardingState,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hydrate(v: unknown) {
|
hydrate(v: unknown) {
|
||||||
if (isObj(v)) {
|
if (isObj(v)) {
|
||||||
const data: SessionData = {
|
if (hasProp(v, 'data') && isObj(v.data)) {
|
||||||
service: '',
|
const data: SessionData = {
|
||||||
token: '',
|
service: '',
|
||||||
username: '',
|
token: '',
|
||||||
userdid: '',
|
username: '',
|
||||||
|
userdid: '',
|
||||||
|
}
|
||||||
|
if (hasProp(v.data, 'service') && typeof v.data.service === 'string') {
|
||||||
|
data.service = v.data.service
|
||||||
|
}
|
||||||
|
if (hasProp(v.data, 'token') && typeof v.data.token === 'string') {
|
||||||
|
data.token = v.data.token
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
hasProp(v.data, 'username') &&
|
||||||
|
typeof v.data.username === 'string'
|
||||||
|
) {
|
||||||
|
data.username = v.data.username
|
||||||
|
}
|
||||||
|
if (hasProp(v.data, 'userdid') && typeof v.data.userdid === 'string') {
|
||||||
|
data.userdid = v.data.userdid
|
||||||
|
}
|
||||||
|
if (data.service && data.token && data.username && data.userdid) {
|
||||||
|
this.data = data
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (hasProp(v, 'service') && typeof v.service === 'string') {
|
if (
|
||||||
data.service = v.service
|
this.data &&
|
||||||
}
|
hasProp(v, 'onboardingState') &&
|
||||||
if (hasProp(v, 'token') && typeof v.token === 'string') {
|
isObj(v.onboardingState)
|
||||||
data.token = v.token
|
) {
|
||||||
}
|
if (
|
||||||
if (hasProp(v, 'username') && typeof v.username === 'string') {
|
hasProp(v.onboardingState, 'stage') &&
|
||||||
data.username = v.username
|
typeof v.onboardingState === 'string'
|
||||||
}
|
) {
|
||||||
if (hasProp(v, 'userdid') && typeof v.userdid === 'string') {
|
this.onboardingState = v.onboardingState
|
||||||
data.userdid = v.userdid
|
}
|
||||||
}
|
|
||||||
if (data.service && data.token && data.username && data.userdid) {
|
|
||||||
this.data = data
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,6 +132,12 @@ export class SessionModel {
|
||||||
this.clear() // invalid session cached
|
this.clear() // invalid session cached
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async describeService(service: string): Promise<ServiceDescription> {
|
||||||
|
const api = AdxApi.service(service)
|
||||||
|
const res = await api.todo.adx.getAccountsConfig({})
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
|
|
||||||
async login({
|
async login({
|
||||||
service,
|
service,
|
||||||
username,
|
username,
|
||||||
|
@ -122,6 +160,36 @@ export class SessionModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async createAccount({
|
||||||
|
service,
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
username,
|
||||||
|
inviteCode,
|
||||||
|
}: {
|
||||||
|
service: string
|
||||||
|
email: string
|
||||||
|
password: string
|
||||||
|
username: string
|
||||||
|
inviteCode?: string
|
||||||
|
}) {
|
||||||
|
const api = AdxApi.service(service)
|
||||||
|
const res = await api.todo.adx.createAccount(
|
||||||
|
{},
|
||||||
|
{username, password, email, inviteCode},
|
||||||
|
)
|
||||||
|
if (res.data.jwt) {
|
||||||
|
this.setState({
|
||||||
|
service: service,
|
||||||
|
token: res.data.jwt,
|
||||||
|
username: res.data.name,
|
||||||
|
userdid: res.data.did,
|
||||||
|
})
|
||||||
|
this.setOnboardingStage(OnboardingStage.Init)
|
||||||
|
this.configureApi()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async logout() {
|
async logout() {
|
||||||
if (this.isAuthed) {
|
if (this.isAuthed) {
|
||||||
this.rootStore.api.todo.adx.deleteSession({}).catch((e: any) => {
|
this.rootStore.api.todo.adx.deleteSession({}).catch((e: any) => {
|
||||||
|
@ -130,4 +198,12 @@ export class SessionModel {
|
||||||
}
|
}
|
||||||
this.clear()
|
this.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setOnboardingStage(stage: OnboardingStage | null) {
|
||||||
|
if (stage === null) {
|
||||||
|
this.onboardingState = null
|
||||||
|
} else {
|
||||||
|
this.onboardingState = {stage}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10253,12 +10253,15 @@ var methodSchemas = [
|
||||||
encoding: "application/json",
|
encoding: "application/json",
|
||||||
schema: {
|
schema: {
|
||||||
type: "object",
|
type: "object",
|
||||||
required: ["username", "did", "password"],
|
required: ["email", "username", "password"],
|
||||||
properties: {
|
properties: {
|
||||||
|
email: {
|
||||||
|
type: "string"
|
||||||
|
},
|
||||||
username: {
|
username: {
|
||||||
type: "string"
|
type: "string"
|
||||||
},
|
},
|
||||||
did: {
|
inviteCode: {
|
||||||
type: "string"
|
type: "string"
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
|
@ -10271,10 +10274,16 @@ var methodSchemas = [
|
||||||
encoding: "application/json",
|
encoding: "application/json",
|
||||||
schema: {
|
schema: {
|
||||||
type: "object",
|
type: "object",
|
||||||
required: ["jwt"],
|
required: ["jwt", "name", "did"],
|
||||||
properties: {
|
properties: {
|
||||||
jwt: {
|
jwt: {
|
||||||
type: "string"
|
type: "string"
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: "string"
|
||||||
|
},
|
||||||
|
did: {
|
||||||
|
type: "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10305,10 +10314,16 @@ var methodSchemas = [
|
||||||
encoding: "application/json",
|
encoding: "application/json",
|
||||||
schema: {
|
schema: {
|
||||||
type: "object",
|
type: "object",
|
||||||
required: ["jwt"],
|
required: ["jwt", "name", "did"],
|
||||||
properties: {
|
properties: {
|
||||||
jwt: {
|
jwt: {
|
||||||
type: "string"
|
type: "string"
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: "string"
|
||||||
|
},
|
||||||
|
did: {
|
||||||
|
type: "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10359,16 +10374,37 @@ var methodSchemas = [
|
||||||
schema: {}
|
schema: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
lexicon: 1,
|
||||||
|
id: "todo.adx.getAccountsConfig",
|
||||||
|
type: "query",
|
||||||
|
description: "Get a document describing the service's accounts configuration.",
|
||||||
|
parameters: {},
|
||||||
|
output: {
|
||||||
|
encoding: "application/json",
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
required: ["availableUserDomains"],
|
||||||
|
properties: {
|
||||||
|
inviteCodeRequired: {
|
||||||
|
type: "boolean"
|
||||||
|
},
|
||||||
|
availableUserDomains: {
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
lexicon: 1,
|
lexicon: 1,
|
||||||
id: "todo.adx.getSession",
|
id: "todo.adx.getSession",
|
||||||
type: "query",
|
type: "query",
|
||||||
description: "Get information about the current session.",
|
description: "Get information about the current session.",
|
||||||
parameters: {},
|
parameters: {},
|
||||||
input: {
|
|
||||||
encoding: "",
|
|
||||||
schema: {}
|
|
||||||
},
|
|
||||||
output: {
|
output: {
|
||||||
encoding: "application/json",
|
encoding: "application/json",
|
||||||
schema: {
|
schema: {
|
||||||
|
@ -11603,6 +11639,14 @@ var AdxNS = class {
|
||||||
getAccount(params, data, opts) {
|
getAccount(params, data, opts) {
|
||||||
return this._service.xrpc.call("todo.adx.getAccount", params, data, opts);
|
return this._service.xrpc.call("todo.adx.getAccount", params, data, opts);
|
||||||
}
|
}
|
||||||
|
getAccountsConfig(params, data, opts) {
|
||||||
|
return this._service.xrpc.call(
|
||||||
|
"todo.adx.getAccountsConfig",
|
||||||
|
params,
|
||||||
|
data,
|
||||||
|
opts
|
||||||
|
);
|
||||||
|
}
|
||||||
getSession(params, data, opts) {
|
getSession(params, data, opts) {
|
||||||
return this._service.xrpc.call("todo.adx.getSession", params, data, opts);
|
return this._service.xrpc.call("todo.adx.getSession", params, data, opts);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -4,6 +4,7 @@ import * as TodoAdxCreateSession from './types/todo/adx/createSession';
|
||||||
import * as TodoAdxDeleteAccount from './types/todo/adx/deleteAccount';
|
import * as TodoAdxDeleteAccount from './types/todo/adx/deleteAccount';
|
||||||
import * as TodoAdxDeleteSession from './types/todo/adx/deleteSession';
|
import * as TodoAdxDeleteSession from './types/todo/adx/deleteSession';
|
||||||
import * as TodoAdxGetAccount from './types/todo/adx/getAccount';
|
import * as TodoAdxGetAccount from './types/todo/adx/getAccount';
|
||||||
|
import * as TodoAdxGetAccountsConfig from './types/todo/adx/getAccountsConfig';
|
||||||
import * as TodoAdxGetSession from './types/todo/adx/getSession';
|
import * as TodoAdxGetSession from './types/todo/adx/getSession';
|
||||||
import * as TodoAdxRepoBatchWrite from './types/todo/adx/repoBatchWrite';
|
import * as TodoAdxRepoBatchWrite from './types/todo/adx/repoBatchWrite';
|
||||||
import * as TodoAdxRepoCreateRecord from './types/todo/adx/repoCreateRecord';
|
import * as TodoAdxRepoCreateRecord from './types/todo/adx/repoCreateRecord';
|
||||||
|
@ -59,6 +60,7 @@ export declare class AdxNS {
|
||||||
deleteAccount(params: TodoAdxDeleteAccount.QueryParams, data?: TodoAdxDeleteAccount.InputSchema, opts?: TodoAdxDeleteAccount.CallOptions): Promise<TodoAdxDeleteAccount.Response>;
|
deleteAccount(params: TodoAdxDeleteAccount.QueryParams, data?: TodoAdxDeleteAccount.InputSchema, opts?: TodoAdxDeleteAccount.CallOptions): Promise<TodoAdxDeleteAccount.Response>;
|
||||||
deleteSession(params: TodoAdxDeleteSession.QueryParams, data?: TodoAdxDeleteSession.InputSchema, opts?: TodoAdxDeleteSession.CallOptions): Promise<TodoAdxDeleteSession.Response>;
|
deleteSession(params: TodoAdxDeleteSession.QueryParams, data?: TodoAdxDeleteSession.InputSchema, opts?: TodoAdxDeleteSession.CallOptions): Promise<TodoAdxDeleteSession.Response>;
|
||||||
getAccount(params: TodoAdxGetAccount.QueryParams, data?: TodoAdxGetAccount.InputSchema, opts?: TodoAdxGetAccount.CallOptions): Promise<TodoAdxGetAccount.Response>;
|
getAccount(params: TodoAdxGetAccount.QueryParams, data?: TodoAdxGetAccount.InputSchema, opts?: TodoAdxGetAccount.CallOptions): Promise<TodoAdxGetAccount.Response>;
|
||||||
|
getAccountsConfig(params: TodoAdxGetAccountsConfig.QueryParams, data?: TodoAdxGetAccountsConfig.InputSchema, opts?: TodoAdxGetAccountsConfig.CallOptions): Promise<TodoAdxGetAccountsConfig.Response>;
|
||||||
getSession(params: TodoAdxGetSession.QueryParams, data?: TodoAdxGetSession.InputSchema, opts?: TodoAdxGetSession.CallOptions): Promise<TodoAdxGetSession.Response>;
|
getSession(params: TodoAdxGetSession.QueryParams, data?: TodoAdxGetSession.InputSchema, opts?: TodoAdxGetSession.CallOptions): Promise<TodoAdxGetSession.Response>;
|
||||||
repoBatchWrite(params: TodoAdxRepoBatchWrite.QueryParams, data?: TodoAdxRepoBatchWrite.InputSchema, opts?: TodoAdxRepoBatchWrite.CallOptions): Promise<TodoAdxRepoBatchWrite.Response>;
|
repoBatchWrite(params: TodoAdxRepoBatchWrite.QueryParams, data?: TodoAdxRepoBatchWrite.InputSchema, opts?: TodoAdxRepoBatchWrite.CallOptions): Promise<TodoAdxRepoBatchWrite.Response>;
|
||||||
repoCreateRecord(params: TodoAdxRepoCreateRecord.QueryParams, data?: TodoAdxRepoCreateRecord.InputSchema, opts?: TodoAdxRepoCreateRecord.CallOptions): Promise<TodoAdxRepoCreateRecord.Response>;
|
repoCreateRecord(params: TodoAdxRepoCreateRecord.QueryParams, data?: TodoAdxRepoCreateRecord.InputSchema, opts?: TodoAdxRepoCreateRecord.CallOptions): Promise<TodoAdxRepoCreateRecord.Response>;
|
||||||
|
|
|
@ -6,12 +6,15 @@ export interface CallOptions {
|
||||||
encoding: 'application/json';
|
encoding: 'application/json';
|
||||||
}
|
}
|
||||||
export interface InputSchema {
|
export interface InputSchema {
|
||||||
|
email: string;
|
||||||
username: string;
|
username: string;
|
||||||
did: string;
|
inviteCode?: string;
|
||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
export interface OutputSchema {
|
export interface OutputSchema {
|
||||||
jwt: string;
|
jwt: string;
|
||||||
|
name: string;
|
||||||
|
did: string;
|
||||||
}
|
}
|
||||||
export interface Response {
|
export interface Response {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
|
|
|
@ -11,6 +11,8 @@ export interface InputSchema {
|
||||||
}
|
}
|
||||||
export interface OutputSchema {
|
export interface OutputSchema {
|
||||||
jwt: string;
|
jwt: string;
|
||||||
|
name: string;
|
||||||
|
did: string;
|
||||||
}
|
}
|
||||||
export interface Response {
|
export interface Response {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { Headers } from '@adxp/xrpc';
|
||||||
|
export interface QueryParams {
|
||||||
|
}
|
||||||
|
export interface CallOptions {
|
||||||
|
headers?: Headers;
|
||||||
|
}
|
||||||
|
export declare type InputSchema = undefined;
|
||||||
|
export interface OutputSchema {
|
||||||
|
inviteCodeRequired?: boolean;
|
||||||
|
availableUserDomains: string[];
|
||||||
|
}
|
||||||
|
export interface Response {
|
||||||
|
success: boolean;
|
||||||
|
error: boolean;
|
||||||
|
headers: Headers;
|
||||||
|
data: OutputSchema;
|
||||||
|
}
|
|
@ -3,11 +3,8 @@ export interface QueryParams {
|
||||||
}
|
}
|
||||||
export interface CallOptions {
|
export interface CallOptions {
|
||||||
headers?: Headers;
|
headers?: Headers;
|
||||||
encoding: '';
|
|
||||||
}
|
|
||||||
export interface InputSchema {
|
|
||||||
[k: string]: unknown;
|
|
||||||
}
|
}
|
||||||
|
export declare type InputSchema = undefined;
|
||||||
export interface OutputSchema {
|
export interface OutputSchema {
|
||||||
name: string;
|
name: string;
|
||||||
did: string;
|
did: string;
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,155 @@
|
||||||
|
import React, {useRef} from 'react'
|
||||||
|
import {
|
||||||
|
StyleProp,
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
TextStyle,
|
||||||
|
TouchableOpacity,
|
||||||
|
TouchableWithoutFeedback,
|
||||||
|
View,
|
||||||
|
ViewStyle,
|
||||||
|
} from 'react-native'
|
||||||
|
import {
|
||||||
|
FontAwesomeIcon,
|
||||||
|
FontAwesomeIconStyle,
|
||||||
|
} from '@fortawesome/react-native-fontawesome'
|
||||||
|
import RootSiblings from 'react-native-root-siblings'
|
||||||
|
import {colors} from '../../lib/styles'
|
||||||
|
|
||||||
|
interface PickerItem {
|
||||||
|
value: string
|
||||||
|
label: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PickerOpts {
|
||||||
|
style?: StyleProp<ViewStyle>
|
||||||
|
labelStyle?: StyleProp<TextStyle>
|
||||||
|
iconStyle?: FontAwesomeIconStyle
|
||||||
|
items: PickerItem[]
|
||||||
|
value: string
|
||||||
|
onChange: (value: string) => void
|
||||||
|
enabled?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const MENU_WIDTH = 200
|
||||||
|
|
||||||
|
export function Picker({
|
||||||
|
style,
|
||||||
|
labelStyle,
|
||||||
|
iconStyle,
|
||||||
|
items,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
enabled,
|
||||||
|
}: PickerOpts) {
|
||||||
|
const ref = useRef<View>(null)
|
||||||
|
const valueLabel = items.find(item => item.value === value)?.label || value
|
||||||
|
const onPress = () => {
|
||||||
|
if (!enabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ref.current?.measure(
|
||||||
|
(
|
||||||
|
_x: number,
|
||||||
|
_y: number,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
pageX: number,
|
||||||
|
pageY: number,
|
||||||
|
) => {
|
||||||
|
createDropdownMenu(pageX, pageY + height, MENU_WIDTH, items, onChange)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<TouchableWithoutFeedback onPress={onPress}>
|
||||||
|
<View style={[styles.outer, style]} ref={ref}>
|
||||||
|
<View style={styles.label}>
|
||||||
|
<Text style={labelStyle}>{valueLabel}</Text>
|
||||||
|
</View>
|
||||||
|
<FontAwesomeIcon icon="angle-down" style={[styles.icon, iconStyle]} />
|
||||||
|
</View>
|
||||||
|
</TouchableWithoutFeedback>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDropdownMenu(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
width: number,
|
||||||
|
items: PickerItem[],
|
||||||
|
onChange: (value: string) => void,
|
||||||
|
): RootSiblings {
|
||||||
|
const onPressItem = (index: number) => {
|
||||||
|
sibling.destroy()
|
||||||
|
onChange(items[index].value)
|
||||||
|
}
|
||||||
|
const onOuterPress = () => sibling.destroy()
|
||||||
|
const sibling = new RootSiblings(
|
||||||
|
(
|
||||||
|
<>
|
||||||
|
<TouchableWithoutFeedback onPress={onOuterPress}>
|
||||||
|
<View style={styles.bg} />
|
||||||
|
</TouchableWithoutFeedback>
|
||||||
|
<View style={[styles.menu, {left: x, top: y, width}]}>
|
||||||
|
{items.map((item, index) => (
|
||||||
|
<TouchableOpacity
|
||||||
|
key={index}
|
||||||
|
style={[styles.menuItem, index !== 0 && styles.menuItemBorder]}
|
||||||
|
onPress={() => onPressItem(index)}>
|
||||||
|
<Text style={styles.menuItemLabel}>{item.label}</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return sibling
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
outer: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
marginRight: 5,
|
||||||
|
},
|
||||||
|
icon: {},
|
||||||
|
bg: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
backgroundColor: '#000',
|
||||||
|
opacity: 0.1,
|
||||||
|
},
|
||||||
|
menu: {
|
||||||
|
position: 'absolute',
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
borderRadius: 14,
|
||||||
|
opacity: 1,
|
||||||
|
paddingVertical: 6,
|
||||||
|
},
|
||||||
|
menuItem: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingVertical: 6,
|
||||||
|
paddingLeft: 15,
|
||||||
|
paddingRight: 30,
|
||||||
|
},
|
||||||
|
menuItemBorder: {
|
||||||
|
borderTopWidth: 1,
|
||||||
|
borderTopColor: colors.gray2,
|
||||||
|
marginTop: 4,
|
||||||
|
paddingTop: 12,
|
||||||
|
},
|
||||||
|
menuItemIcon: {
|
||||||
|
marginLeft: 6,
|
||||||
|
marginRight: 8,
|
||||||
|
},
|
||||||
|
menuItemLabel: {
|
||||||
|
fontSize: 15,
|
||||||
|
},
|
||||||
|
})
|
|
@ -1,5 +1,6 @@
|
||||||
import {library} from '@fortawesome/fontawesome-svg-core'
|
import {library} from '@fortawesome/fontawesome-svg-core'
|
||||||
|
|
||||||
|
import {faAngleDown} from '@fortawesome/free-solid-svg-icons/faAngleDown'
|
||||||
import {faAngleLeft} from '@fortawesome/free-solid-svg-icons/faAngleLeft'
|
import {faAngleLeft} from '@fortawesome/free-solid-svg-icons/faAngleLeft'
|
||||||
import {faAngleRight} from '@fortawesome/free-solid-svg-icons/faAngleRight'
|
import {faAngleRight} from '@fortawesome/free-solid-svg-icons/faAngleRight'
|
||||||
import {faArrowLeft} from '@fortawesome/free-solid-svg-icons/faArrowLeft'
|
import {faArrowLeft} from '@fortawesome/free-solid-svg-icons/faArrowLeft'
|
||||||
|
@ -7,6 +8,7 @@ import {faArrowRightFromBracket} from '@fortawesome/free-solid-svg-icons'
|
||||||
import {faArrowUpFromBracket} from '@fortawesome/free-solid-svg-icons/faArrowUpFromBracket'
|
import {faArrowUpFromBracket} from '@fortawesome/free-solid-svg-icons/faArrowUpFromBracket'
|
||||||
import {faArrowUpRightFromSquare} from '@fortawesome/free-solid-svg-icons/faArrowUpRightFromSquare'
|
import {faArrowUpRightFromSquare} from '@fortawesome/free-solid-svg-icons/faArrowUpRightFromSquare'
|
||||||
import {faArrowsRotate} from '@fortawesome/free-solid-svg-icons/faArrowsRotate'
|
import {faArrowsRotate} from '@fortawesome/free-solid-svg-icons/faArrowsRotate'
|
||||||
|
import {faAt} from '@fortawesome/free-solid-svg-icons/faAt'
|
||||||
import {faBars} from '@fortawesome/free-solid-svg-icons/faBars'
|
import {faBars} from '@fortawesome/free-solid-svg-icons/faBars'
|
||||||
import {faBell} from '@fortawesome/free-solid-svg-icons/faBell'
|
import {faBell} from '@fortawesome/free-solid-svg-icons/faBell'
|
||||||
import {faBell as farBell} from '@fortawesome/free-regular-svg-icons/faBell'
|
import {faBell as farBell} from '@fortawesome/free-regular-svg-icons/faBell'
|
||||||
|
@ -16,12 +18,15 @@ import {faCheck} from '@fortawesome/free-solid-svg-icons/faCheck'
|
||||||
import {faClone} from '@fortawesome/free-regular-svg-icons/faClone'
|
import {faClone} from '@fortawesome/free-regular-svg-icons/faClone'
|
||||||
import {faComment} from '@fortawesome/free-regular-svg-icons/faComment'
|
import {faComment} from '@fortawesome/free-regular-svg-icons/faComment'
|
||||||
import {faEllipsis} from '@fortawesome/free-solid-svg-icons/faEllipsis'
|
import {faEllipsis} from '@fortawesome/free-solid-svg-icons/faEllipsis'
|
||||||
|
import {faEnvelope} from '@fortawesome/free-solid-svg-icons/faEnvelope'
|
||||||
import {faExclamation} from '@fortawesome/free-solid-svg-icons/faExclamation'
|
import {faExclamation} from '@fortawesome/free-solid-svg-icons/faExclamation'
|
||||||
import {faGear} from '@fortawesome/free-solid-svg-icons/faGear'
|
import {faGear} from '@fortawesome/free-solid-svg-icons/faGear'
|
||||||
|
import {faGlobe} from '@fortawesome/free-solid-svg-icons/faGlobe'
|
||||||
import {faHeart} from '@fortawesome/free-regular-svg-icons/faHeart'
|
import {faHeart} from '@fortawesome/free-regular-svg-icons/faHeart'
|
||||||
import {faHeart as fasHeart} from '@fortawesome/free-solid-svg-icons/faHeart'
|
import {faHeart as fasHeart} from '@fortawesome/free-solid-svg-icons/faHeart'
|
||||||
import {faHouse} from '@fortawesome/free-solid-svg-icons/faHouse'
|
import {faHouse} from '@fortawesome/free-solid-svg-icons/faHouse'
|
||||||
import {faLink} from '@fortawesome/free-solid-svg-icons/faLink'
|
import {faLink} from '@fortawesome/free-solid-svg-icons/faLink'
|
||||||
|
import {faLock} from '@fortawesome/free-solid-svg-icons/faLock'
|
||||||
import {faMagnifyingGlass} from '@fortawesome/free-solid-svg-icons/faMagnifyingGlass'
|
import {faMagnifyingGlass} from '@fortawesome/free-solid-svg-icons/faMagnifyingGlass'
|
||||||
import {faMessage} from '@fortawesome/free-regular-svg-icons/faMessage'
|
import {faMessage} from '@fortawesome/free-regular-svg-icons/faMessage'
|
||||||
import {faPenNib} from '@fortawesome/free-solid-svg-icons/faPenNib'
|
import {faPenNib} from '@fortawesome/free-solid-svg-icons/faPenNib'
|
||||||
|
@ -32,10 +37,12 @@ import {faShield} from '@fortawesome/free-solid-svg-icons/faShield'
|
||||||
import {faRetweet} from '@fortawesome/free-solid-svg-icons/faRetweet'
|
import {faRetweet} from '@fortawesome/free-solid-svg-icons/faRetweet'
|
||||||
import {faUser} from '@fortawesome/free-regular-svg-icons/faUser'
|
import {faUser} from '@fortawesome/free-regular-svg-icons/faUser'
|
||||||
import {faUsers} from '@fortawesome/free-solid-svg-icons/faUsers'
|
import {faUsers} from '@fortawesome/free-solid-svg-icons/faUsers'
|
||||||
|
import {faTicket} from '@fortawesome/free-solid-svg-icons/faTicket'
|
||||||
import {faX} from '@fortawesome/free-solid-svg-icons/faX'
|
import {faX} from '@fortawesome/free-solid-svg-icons/faX'
|
||||||
|
|
||||||
export function setup() {
|
export function setup() {
|
||||||
library.add(
|
library.add(
|
||||||
|
faAngleDown,
|
||||||
faAngleLeft,
|
faAngleLeft,
|
||||||
faAngleRight,
|
faAngleRight,
|
||||||
faArrowLeft,
|
faArrowLeft,
|
||||||
|
@ -43,6 +50,7 @@ export function setup() {
|
||||||
faArrowUpFromBracket,
|
faArrowUpFromBracket,
|
||||||
faArrowUpRightFromSquare,
|
faArrowUpRightFromSquare,
|
||||||
faArrowsRotate,
|
faArrowsRotate,
|
||||||
|
faAt,
|
||||||
faBars,
|
faBars,
|
||||||
faBell,
|
faBell,
|
||||||
farBell,
|
farBell,
|
||||||
|
@ -52,12 +60,15 @@ export function setup() {
|
||||||
faClone,
|
faClone,
|
||||||
faComment,
|
faComment,
|
||||||
faEllipsis,
|
faEllipsis,
|
||||||
|
faEnvelope,
|
||||||
faExclamation,
|
faExclamation,
|
||||||
faGear,
|
faGear,
|
||||||
|
faGlobe,
|
||||||
faHeart,
|
faHeart,
|
||||||
fasHeart,
|
fasHeart,
|
||||||
faHouse,
|
faHouse,
|
||||||
faLink,
|
faLink,
|
||||||
|
faLock,
|
||||||
faMagnifyingGlass,
|
faMagnifyingGlass,
|
||||||
faMessage,
|
faMessage,
|
||||||
faPenNib,
|
faPenNib,
|
||||||
|
@ -68,6 +79,7 @@ export function setup() {
|
||||||
faShield,
|
faShield,
|
||||||
faUser,
|
faUser,
|
||||||
faUsers,
|
faUsers,
|
||||||
|
faTicket,
|
||||||
faX,
|
faX,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ export const colors = {
|
||||||
gray4: '#968d8d',
|
gray4: '#968d8d',
|
||||||
gray5: '#645454',
|
gray5: '#645454',
|
||||||
|
|
||||||
|
blue0: '#bfe1ff',
|
||||||
blue1: '#8bc7fd',
|
blue1: '#8bc7fd',
|
||||||
blue2: '#52acfe',
|
blue2: '#52acfe',
|
||||||
blue3: '#0085ff',
|
blue3: '#0085ff',
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, {useState} from 'react'
|
import React, {useState, useEffect} from 'react'
|
||||||
import {
|
import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
KeyboardAvoidingView,
|
KeyboardAvoidingView,
|
||||||
|
@ -11,85 +11,69 @@ import {
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import Svg, {Circle, Line, Text as SvgText} from 'react-native-svg'
|
import Svg, {Circle, Line, Text as SvgText} from 'react-native-svg'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
|
import * as EmailValidator from 'email-validator'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
|
import {Picker} from '../com/util/Picker'
|
||||||
import {s, colors} from '../lib/styles'
|
import {s, colors} from '../lib/styles'
|
||||||
import {useStores} from '../../state'
|
import {useStores} from '../../state'
|
||||||
|
import {ServiceDescription} from '../../state/models/session'
|
||||||
|
|
||||||
enum ScreenState {
|
enum ScreenState {
|
||||||
SigninOrCreateAccount,
|
SigninOrCreateAccount,
|
||||||
Signin,
|
Signin,
|
||||||
|
CreateAccount,
|
||||||
|
}
|
||||||
|
|
||||||
|
const Logo = () => {
|
||||||
|
return (
|
||||||
|
<View style={styles.logo}>
|
||||||
|
<Svg width="100" height="100">
|
||||||
|
<Circle
|
||||||
|
cx="50"
|
||||||
|
cy="50"
|
||||||
|
r="46"
|
||||||
|
fill="none"
|
||||||
|
stroke="white"
|
||||||
|
strokeWidth={2}
|
||||||
|
/>
|
||||||
|
<Line stroke="white" strokeWidth={1} x1="30" x2="30" y1="0" y2="100" />
|
||||||
|
<Line stroke="white" strokeWidth={1} x1="74" x2="74" y1="0" y2="100" />
|
||||||
|
<Line stroke="white" strokeWidth={1} x1="0" x2="100" y1="22" y2="22" />
|
||||||
|
<Line stroke="white" strokeWidth={1} x1="0" x2="100" y1="74" y2="74" />
|
||||||
|
<SvgText
|
||||||
|
fill="none"
|
||||||
|
stroke="white"
|
||||||
|
strokeWidth={2}
|
||||||
|
fontSize="60"
|
||||||
|
fontWeight="bold"
|
||||||
|
x="52"
|
||||||
|
y="70"
|
||||||
|
textAnchor="middle">
|
||||||
|
B
|
||||||
|
</SvgText>
|
||||||
|
</Svg>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const SigninOrCreateAccount = ({
|
const SigninOrCreateAccount = ({
|
||||||
onPressSignin,
|
onPressSignin,
|
||||||
|
onPressCreateAccount,
|
||||||
}: {
|
}: {
|
||||||
onPressSignin: () => void
|
onPressSignin: () => void
|
||||||
|
onPressCreateAccount: () => void
|
||||||
}) => {
|
}) => {
|
||||||
const winDim = useWindowDimensions()
|
const winDim = useWindowDimensions()
|
||||||
const halfWidth = winDim.width / 2
|
const halfWidth = winDim.width / 2
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<View style={styles.hero}>
|
<View style={styles.hero}>
|
||||||
<View style={styles.logo}>
|
<Logo />
|
||||||
<Svg width="100" height="100">
|
|
||||||
<Circle
|
|
||||||
cx="50"
|
|
||||||
cy="50"
|
|
||||||
r="46"
|
|
||||||
fill="none"
|
|
||||||
stroke="white"
|
|
||||||
strokeWidth={2}
|
|
||||||
/>
|
|
||||||
<Line
|
|
||||||
stroke="white"
|
|
||||||
strokeWidth={1}
|
|
||||||
x1="30"
|
|
||||||
x2="30"
|
|
||||||
y1="0"
|
|
||||||
y2="100"
|
|
||||||
/>
|
|
||||||
<Line
|
|
||||||
stroke="white"
|
|
||||||
strokeWidth={1}
|
|
||||||
x1="74"
|
|
||||||
x2="74"
|
|
||||||
y1="0"
|
|
||||||
y2="100"
|
|
||||||
/>
|
|
||||||
<Line
|
|
||||||
stroke="white"
|
|
||||||
strokeWidth={1}
|
|
||||||
x1="0"
|
|
||||||
x2="100"
|
|
||||||
y1="22"
|
|
||||||
y2="22"
|
|
||||||
/>
|
|
||||||
<Line
|
|
||||||
stroke="white"
|
|
||||||
strokeWidth={1}
|
|
||||||
x1="0"
|
|
||||||
x2="100"
|
|
||||||
y1="74"
|
|
||||||
y2="74"
|
|
||||||
/>
|
|
||||||
<SvgText
|
|
||||||
fill="none"
|
|
||||||
stroke="white"
|
|
||||||
strokeWidth={2}
|
|
||||||
fontSize="60"
|
|
||||||
fontWeight="bold"
|
|
||||||
x="52"
|
|
||||||
y="70"
|
|
||||||
textAnchor="middle">
|
|
||||||
B
|
|
||||||
</SvgText>
|
|
||||||
</Svg>
|
|
||||||
</View>
|
|
||||||
<Text style={styles.title}>Bluesky</Text>
|
<Text style={styles.title}>Bluesky</Text>
|
||||||
<Text style={styles.subtitle}>[ private beta ]</Text>
|
<Text style={styles.subtitle}>[ private beta ]</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={s.flex1}>
|
<View style={s.flex1}>
|
||||||
<TouchableOpacity style={styles.btn}>
|
<TouchableOpacity style={styles.btn} onPress={onPressCreateAccount}>
|
||||||
<Text style={styles.btnLabel}>Create a new account</Text>
|
<Text style={styles.btnLabel}>Create a new account</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<View style={styles.or}>
|
<View style={styles.or}>
|
||||||
|
@ -155,31 +139,221 @@ const Signin = ({onPressBack}: {onPressBack: () => void}) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<KeyboardAvoidingView behavior="padding" style={{flex: 1}}>
|
<KeyboardAvoidingView behavior="padding" style={{flex: 1}}>
|
||||||
<View style={styles.smallHero}>
|
<View style={styles.logoHero}>
|
||||||
<Text style={styles.title}>Bluesky</Text>
|
<Logo />
|
||||||
<Text style={styles.subtitle}>[ private beta ]</Text>
|
|
||||||
</View>
|
</View>
|
||||||
<View style={s.flex1}>
|
<View style={styles.group}>
|
||||||
<View style={styles.group}>
|
<View style={styles.groupTitle}>
|
||||||
<View style={styles.groupTitle}>
|
<Text style={[s.white, s.f18, s.bold]}>Sign in</Text>
|
||||||
<Text style={[s.white, s.f18]}>Sign in</Text>
|
</View>
|
||||||
|
{error ? (
|
||||||
|
<View style={styles.error}>
|
||||||
|
<View style={styles.errorIcon}>
|
||||||
|
<FontAwesomeIcon icon="exclamation" style={s.white} size={10} />
|
||||||
|
</View>
|
||||||
|
<View style={s.flex1}>
|
||||||
|
<Text style={[s.white, s.bold]}>{error}</Text>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.groupContent}>
|
) : undefined}
|
||||||
<View style={[s.mb5]}>
|
<View style={styles.groupContent}>
|
||||||
|
<FontAwesomeIcon icon="envelope" style={styles.groupContentIcon} />
|
||||||
|
<TextInput
|
||||||
|
style={styles.textInput}
|
||||||
|
placeholder="Email or username"
|
||||||
|
placeholderTextColor={colors.blue0}
|
||||||
|
autoCapitalize="none"
|
||||||
|
autoFocus
|
||||||
|
value={username}
|
||||||
|
onChangeText={setUsername}
|
||||||
|
editable={!isProcessing}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.groupContent}>
|
||||||
|
<FontAwesomeIcon icon="lock" style={styles.groupContentIcon} />
|
||||||
|
<TextInput
|
||||||
|
style={styles.textInput}
|
||||||
|
placeholder="Password"
|
||||||
|
placeholderTextColor={colors.blue0}
|
||||||
|
autoCapitalize="none"
|
||||||
|
secureTextEntry
|
||||||
|
value={password}
|
||||||
|
onChangeText={setPassword}
|
||||||
|
editable={!isProcessing}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={[s.flexRow, s.pl20, s.pr20]}>
|
||||||
|
<TouchableOpacity onPress={onPressBack}>
|
||||||
|
<Text style={[s.white, s.f18, s.pl5]}>Back</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<View style={s.flex1} />
|
||||||
|
<TouchableOpacity onPress={onPressNext}>
|
||||||
|
{isProcessing ? (
|
||||||
|
<ActivityIndicator color="#fff" />
|
||||||
|
) : (
|
||||||
|
<Text style={[s.white, s.f18, s.bold, s.pr5]}>Next</Text>
|
||||||
|
)}
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</KeyboardAvoidingView>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const CreateAccount = ({onPressBack}: {onPressBack: () => void}) => {
|
||||||
|
const store = useStores()
|
||||||
|
const [isProcessing, setIsProcessing] = useState<boolean>(false)
|
||||||
|
const [error, setError] = useState<string>('')
|
||||||
|
const [serviceDescription, setServiceDescription] = useState<
|
||||||
|
ServiceDescription | undefined
|
||||||
|
>(undefined)
|
||||||
|
const [userDomain, setUserDomain] = useState<string>('')
|
||||||
|
const [inviteCode, setInviteCode] = useState<string>('')
|
||||||
|
const [email, setEmail] = useState<string>('')
|
||||||
|
const [password, setPassword] = useState<string>('')
|
||||||
|
const [username, setUsername] = useState<string>('')
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (serviceDescription || error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
store.session.describeService('http://localhost:2583/').then(
|
||||||
|
desc => {
|
||||||
|
setServiceDescription(desc)
|
||||||
|
setUserDomain(desc.availableUserDomains[0])
|
||||||
|
},
|
||||||
|
err => {
|
||||||
|
console.error(err)
|
||||||
|
setError(
|
||||||
|
'Unable to contact your service. Please check your Internet connection.',
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const onPressNext = async () => {
|
||||||
|
if (!email) {
|
||||||
|
return setError('Please enter your email.')
|
||||||
|
}
|
||||||
|
if (!EmailValidator.validate(email)) {
|
||||||
|
return setError('Your email appears to be invalid.')
|
||||||
|
}
|
||||||
|
if (!password) {
|
||||||
|
return setError('Please choose your password.')
|
||||||
|
}
|
||||||
|
if (!username) {
|
||||||
|
return setError('Please choose your username.')
|
||||||
|
}
|
||||||
|
setError('')
|
||||||
|
setIsProcessing(true)
|
||||||
|
try {
|
||||||
|
await store.session.createAccount({
|
||||||
|
service: 'http://localhost:2583/',
|
||||||
|
email,
|
||||||
|
username: `${username}.${userDomain}`,
|
||||||
|
password,
|
||||||
|
inviteCode,
|
||||||
|
})
|
||||||
|
} catch (e: any) {
|
||||||
|
const errMsg = e.toString()
|
||||||
|
console.log(e)
|
||||||
|
setIsProcessing(false)
|
||||||
|
// if (errMsg.includes('Authentication Required')) {
|
||||||
|
// setError('Invalid username or password')
|
||||||
|
// } else if (errMsg.includes('Network request failed')) {
|
||||||
|
// setError(
|
||||||
|
// 'Unable to contact your service. Please check your Internet connection.',
|
||||||
|
// )
|
||||||
|
// } else {
|
||||||
|
setError(errMsg.replace(/^Error:/, ''))
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const InitialLoadView = () => (
|
||||||
|
<>
|
||||||
|
{error ? (
|
||||||
|
<>
|
||||||
|
<View style={[styles.error, styles.errorFloating]}>
|
||||||
|
<View style={styles.errorIcon}>
|
||||||
|
<FontAwesomeIcon icon="exclamation" style={s.white} size={10} />
|
||||||
|
</View>
|
||||||
|
<View style={s.flex1}>
|
||||||
|
<Text style={[s.white, s.bold]}>{error}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={[s.flexRow, s.pl20, s.pr20]}>
|
||||||
|
<TouchableOpacity onPress={onPressBack}>
|
||||||
|
<Text style={[s.white, s.f18, s.pl5]}>Back</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<ActivityIndicator color="#fff" />
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<KeyboardAvoidingView behavior="padding" style={{flex: 1}}>
|
||||||
|
<View style={styles.logoHero}>
|
||||||
|
<Logo />
|
||||||
|
</View>
|
||||||
|
{serviceDescription ? (
|
||||||
|
<>
|
||||||
|
{error ? (
|
||||||
|
<View style={[styles.error, styles.errorFloating]}>
|
||||||
|
<View style={styles.errorIcon}>
|
||||||
|
<FontAwesomeIcon icon="exclamation" style={s.white} size={10} />
|
||||||
|
</View>
|
||||||
|
<View style={s.flex1}>
|
||||||
|
<Text style={[s.white, s.bold]}>{error}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
) : undefined}
|
||||||
|
<View style={styles.group}>
|
||||||
|
<View style={styles.groupTitle}>
|
||||||
|
<Text style={[s.white, s.f18, s.bold]}>Create a new account</Text>
|
||||||
|
</View>
|
||||||
|
{serviceDescription?.inviteCodeRequired ? (
|
||||||
|
<View style={styles.groupContent}>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon="ticket"
|
||||||
|
style={styles.groupContentIcon}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
style={[styles.textInput]}
|
||||||
|
placeholder="Invite code"
|
||||||
|
placeholderTextColor={colors.blue0}
|
||||||
|
autoCapitalize="none"
|
||||||
|
autoFocus
|
||||||
|
value={inviteCode}
|
||||||
|
onChangeText={setInviteCode}
|
||||||
|
editable={!isProcessing}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
) : undefined}
|
||||||
|
<View style={styles.groupContent}>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon="envelope"
|
||||||
|
style={styles.groupContentIcon}
|
||||||
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={styles.textInput}
|
style={[styles.textInput]}
|
||||||
placeholder="Email or username"
|
placeholder="Email address"
|
||||||
|
placeholderTextColor={colors.blue0}
|
||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoFocus
|
value={email}
|
||||||
value={username}
|
onChangeText={setEmail}
|
||||||
onChangeText={setUsername}
|
|
||||||
editable={!isProcessing}
|
editable={!isProcessing}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={[s.mb5]}>
|
<View style={styles.groupContent}>
|
||||||
|
<FontAwesomeIcon icon="lock" style={styles.groupContentIcon} />
|
||||||
<TextInput
|
<TextInput
|
||||||
style={styles.textInput}
|
style={[styles.textInput]}
|
||||||
placeholder="Password"
|
placeholder="Choose your password"
|
||||||
|
placeholderTextColor={colors.blue0}
|
||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
secureTextEntry
|
secureTextEntry
|
||||||
value={password}
|
value={password}
|
||||||
|
@ -187,54 +361,94 @@ const Signin = ({onPressBack}: {onPressBack: () => void}) => {
|
||||||
editable={!isProcessing}
|
editable={!isProcessing}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
{error ? (
|
|
||||||
<View style={styles.error}>
|
|
||||||
<View style={styles.errorIcon}>
|
|
||||||
<FontAwesomeIcon
|
|
||||||
icon="exclamation"
|
|
||||||
style={s.white}
|
|
||||||
size={10}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
<View style={s.flex1}>
|
|
||||||
<Text style={[s.white, s.bold]}>{error}</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
) : undefined}
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
<View style={styles.group}>
|
||||||
<View style={[s.flexRow, s.pl20, s.pr20]}>
|
<View style={styles.groupTitle}>
|
||||||
<TouchableOpacity onPress={onPressBack}>
|
<Text style={[s.white, s.f18, s.bold]}>Choose your username</Text>
|
||||||
<Text style={[s.white, s.f18, s.bold, s.pl5]}>Back</Text>
|
</View>
|
||||||
</TouchableOpacity>
|
<View style={styles.groupContent}>
|
||||||
<View style={s.flex1} />
|
<FontAwesomeIcon icon="at" style={styles.groupContentIcon} />
|
||||||
<TouchableOpacity onPress={onPressNext}>
|
<TextInput
|
||||||
{isProcessing ? (
|
style={[styles.textInput]}
|
||||||
<ActivityIndicator color="#fff" />
|
placeholder="eg alice"
|
||||||
) : (
|
placeholderTextColor={colors.blue0}
|
||||||
<Text style={[s.white, s.f18, s.bold, s.pr5]}>Next</Text>
|
autoCapitalize="none"
|
||||||
|
value={username}
|
||||||
|
onChangeText={v => setUsername(cleanUsername(v))}
|
||||||
|
editable={!isProcessing}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
{serviceDescription.availableUserDomains.length > 1 && (
|
||||||
|
<View style={styles.groupContent}>
|
||||||
|
<FontAwesomeIcon icon="globe" style={styles.groupContentIcon} />
|
||||||
|
<Picker
|
||||||
|
style={styles.picker}
|
||||||
|
labelStyle={styles.pickerLabel}
|
||||||
|
iconStyle={styles.pickerIcon}
|
||||||
|
value={userDomain}
|
||||||
|
items={serviceDescription.availableUserDomains.map(d => ({
|
||||||
|
label: `.${d}`,
|
||||||
|
value: d,
|
||||||
|
}))}
|
||||||
|
onChange={itemValue => setUserDomain(itemValue)}
|
||||||
|
enabled={!isProcessing}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
)}
|
)}
|
||||||
</TouchableOpacity>
|
<View style={styles.groupContent}>
|
||||||
</View>
|
<Text style={[s.white, s.p10]}>
|
||||||
</View>
|
Your full username will be{' '}
|
||||||
|
<Text style={s.bold}>
|
||||||
|
@{username}.{userDomain}
|
||||||
|
</Text>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={[s.flexRow, s.pl20, s.pr20]}>
|
||||||
|
<TouchableOpacity onPress={onPressBack}>
|
||||||
|
<Text style={[s.white, s.f18, s.pl5]}>Back</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<View style={s.flex1} />
|
||||||
|
<TouchableOpacity onPress={onPressNext}>
|
||||||
|
{isProcessing ? (
|
||||||
|
<ActivityIndicator color="#fff" />
|
||||||
|
) : (
|
||||||
|
<Text style={[s.white, s.f18, s.bold, s.pr5]}>Next</Text>
|
||||||
|
)}
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<InitialLoadView />
|
||||||
|
)}
|
||||||
</KeyboardAvoidingView>
|
</KeyboardAvoidingView>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cleanUsername(v: string): string {
|
||||||
|
v = v.trim()
|
||||||
|
if (v.length > 63) {
|
||||||
|
v = v.slice(0, 63)
|
||||||
|
}
|
||||||
|
return v.toLowerCase().replace(/[^a-z0-9-]/g, '')
|
||||||
|
}
|
||||||
|
|
||||||
export const Login = observer(
|
export const Login = observer(
|
||||||
(/*{navigation}: RootTabsScreenProps<'Login'>*/) => {
|
(/*{navigation}: RootTabsScreenProps<'Login'>*/) => {
|
||||||
// const store = useStores()
|
// const store = useStores()
|
||||||
const [screenState, setScreenState] = useState<ScreenState>(
|
const [screenState, setScreenState] = useState<ScreenState>(
|
||||||
ScreenState.SigninOrCreateAccount,
|
ScreenState.SigninOrCreateAccount,
|
||||||
)
|
)
|
||||||
const onPressSignin = () => {
|
|
||||||
setScreenState(ScreenState.Signin)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.outer}>
|
<View style={styles.outer}>
|
||||||
{screenState === ScreenState.SigninOrCreateAccount ? (
|
{screenState === ScreenState.SigninOrCreateAccount ? (
|
||||||
<SigninOrCreateAccount onPressSignin={onPressSignin} />
|
<SigninOrCreateAccount
|
||||||
|
onPressSignin={() => setScreenState(ScreenState.Signin)}
|
||||||
|
onPressCreateAccount={() =>
|
||||||
|
setScreenState(ScreenState.CreateAccount)
|
||||||
|
}
|
||||||
|
/>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{screenState === ScreenState.Signin ? (
|
{screenState === ScreenState.Signin ? (
|
||||||
<Signin
|
<Signin
|
||||||
|
@ -243,6 +457,13 @@ export const Login = observer(
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
|
{screenState === ScreenState.CreateAccount ? (
|
||||||
|
<CreateAccount
|
||||||
|
onPressBack={() =>
|
||||||
|
setScreenState(ScreenState.SigninOrCreateAccount)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
) : undefined}
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -256,9 +477,9 @@ const styles = StyleSheet.create({
|
||||||
flex: 2,
|
flex: 2,
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
},
|
},
|
||||||
smallHero: {
|
logoHero: {
|
||||||
flex: 1,
|
paddingTop: 30,
|
||||||
justifyContent: 'center',
|
paddingBottom: 40,
|
||||||
},
|
},
|
||||||
logo: {
|
logo: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
@ -282,6 +503,7 @@ const styles = StyleSheet.create({
|
||||||
paddingVertical: 16,
|
paddingVertical: 16,
|
||||||
marginBottom: 20,
|
marginBottom: 20,
|
||||||
marginHorizontal: 20,
|
marginHorizontal: 20,
|
||||||
|
backgroundColor: colors.blue3,
|
||||||
},
|
},
|
||||||
btnLabel: {
|
btnLabel: {
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
|
@ -307,33 +529,65 @@ const styles = StyleSheet.create({
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
marginBottom: 20,
|
marginBottom: 20,
|
||||||
marginHorizontal: 20,
|
marginHorizontal: 20,
|
||||||
|
backgroundColor: colors.blue3,
|
||||||
},
|
},
|
||||||
groupTitle: {
|
groupTitle: {
|
||||||
paddingVertical: 8,
|
paddingVertical: 8,
|
||||||
paddingHorizontal: 12,
|
paddingHorizontal: 12,
|
||||||
borderBottomWidth: 1,
|
|
||||||
borderBottomColor: colors.blue1,
|
|
||||||
},
|
},
|
||||||
groupContent: {
|
groupContent: {
|
||||||
paddingVertical: 8,
|
borderTopWidth: 1,
|
||||||
paddingHorizontal: 12,
|
borderTopColor: colors.blue1,
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
groupContentIcon: {
|
||||||
|
color: 'white',
|
||||||
|
marginLeft: 10,
|
||||||
},
|
},
|
||||||
textInput: {
|
textInput: {
|
||||||
|
flex: 1,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
backgroundColor: colors.white,
|
backgroundColor: colors.blue3,
|
||||||
paddingHorizontal: 8,
|
color: colors.white,
|
||||||
paddingVertical: 8,
|
paddingVertical: 10,
|
||||||
borderRadius: 4,
|
paddingHorizontal: 12,
|
||||||
|
fontSize: 18,
|
||||||
|
borderRadius: 10,
|
||||||
|
},
|
||||||
|
picker: {
|
||||||
|
flex: 1,
|
||||||
|
width: '100%',
|
||||||
|
backgroundColor: colors.blue3,
|
||||||
|
color: colors.white,
|
||||||
|
paddingVertical: 10,
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
fontSize: 18,
|
||||||
|
borderRadius: 10,
|
||||||
|
},
|
||||||
|
pickerLabel: {
|
||||||
|
color: colors.white,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
},
|
},
|
||||||
|
pickerIcon: {
|
||||||
|
color: colors.white,
|
||||||
|
},
|
||||||
error: {
|
error: {
|
||||||
|
borderTopWidth: 1,
|
||||||
|
borderTopColor: colors.blue1,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
marginTop: 5,
|
marginTop: 5,
|
||||||
backgroundColor: colors.purple3,
|
backgroundColor: colors.blue2,
|
||||||
paddingHorizontal: 8,
|
paddingHorizontal: 8,
|
||||||
paddingVertical: 5,
|
paddingVertical: 5,
|
||||||
borderRadius: 4,
|
},
|
||||||
|
errorFloating: {
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: colors.blue1,
|
||||||
|
marginBottom: 20,
|
||||||
|
marginHorizontal: 20,
|
||||||
|
borderRadius: 8,
|
||||||
},
|
},
|
||||||
errorIcon: {
|
errorIcon: {
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
|
|
|
@ -12,7 +12,6 @@ import {
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {ScreenContainer, Screen} from 'react-native-screens'
|
import {ScreenContainer, Screen} from 'react-native-screens'
|
||||||
import LinearGradient from 'react-native-linear-gradient'
|
import LinearGradient from 'react-native-linear-gradient'
|
||||||
// import Svg, {Polygon} from 'react-native-svg'
|
|
||||||
import {GestureDetector, Gesture} from 'react-native-gesture-handler'
|
import {GestureDetector, Gesture} from 'react-native-gesture-handler'
|
||||||
import Animated, {
|
import Animated, {
|
||||||
useSharedValue,
|
useSharedValue,
|
||||||
|
@ -33,7 +32,7 @@ import {LocationNavigator} from './location-navigator'
|
||||||
import {createBackMenu, createForwardMenu} from './history-menu'
|
import {createBackMenu, createForwardMenu} from './history-menu'
|
||||||
import {createAccountsMenu} from './accounts-menu'
|
import {createAccountsMenu} from './accounts-menu'
|
||||||
import {createLocationMenu} from './location-menu'
|
import {createLocationMenu} from './location-menu'
|
||||||
import {s, colors, gradients} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
import {AVIS} from '../../lib/assets'
|
import {AVIS} from '../../lib/assets'
|
||||||
|
|
||||||
const locationIconNeedsNudgeUp = (icon: IconProp) => icon === 'house'
|
const locationIconNeedsNudgeUp = (icon: IconProp) => icon === 'house'
|
||||||
|
@ -174,40 +173,8 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
<LinearGradient
|
<LinearGradient
|
||||||
colors={['#007CFF', '#00BCFF']}
|
colors={['#007CFF', '#00BCFF']}
|
||||||
start={{x: 0, y: 0.8}}
|
start={{x: 0, y: 0.8}}
|
||||||
end={{x: 1, y: 1}}
|
end={{x: 0, y: 1}}
|
||||||
style={styles.outerContainer}>
|
style={styles.outerContainer}>
|
||||||
{
|
|
||||||
undefined /* TODO want this? <Svg height={winDim.height} width={winDim.width} style={s.absolute}>
|
|
||||||
<Polygon
|
|
||||||
points={`
|
|
||||||
${winDim.width},0
|
|
||||||
${winDim.width - 250},0
|
|
||||||
0,${winDim.height - 140}
|
|
||||||
0,${winDim.height}
|
|
||||||
${winDim.width},${winDim.height}`}
|
|
||||||
fill="#fff"
|
|
||||||
fillOpacity="0.04"
|
|
||||||
/>
|
|
||||||
<Polygon
|
|
||||||
points={`
|
|
||||||
${winDim.width},0
|
|
||||||
${winDim.width - 100},0
|
|
||||||
0,${winDim.height - 60}
|
|
||||||
0,${winDim.height}
|
|
||||||
${winDim.width},${winDim.height}`}
|
|
||||||
fill="#fff"
|
|
||||||
fillOpacity="0.04"
|
|
||||||
/>
|
|
||||||
<Polygon
|
|
||||||
points={`
|
|
||||||
${winDim.width},100
|
|
||||||
0,${winDim.height}
|
|
||||||
${winDim.width},${winDim.height}`}
|
|
||||||
fill="#fff"
|
|
||||||
fillOpacity="0.04"
|
|
||||||
/>
|
|
||||||
</Svg>*/
|
|
||||||
}
|
|
||||||
<SafeAreaView style={styles.innerContainer}>
|
<SafeAreaView style={styles.innerContainer}>
|
||||||
<Login />
|
<Login />
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
|
|
82
yarn.lock
82
yarn.lock
|
@ -2195,54 +2195,6 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sinonjs/commons" "^1.7.0"
|
"@sinonjs/commons" "^1.7.0"
|
||||||
|
|
||||||
"@stablelib/binary@^1.0.1":
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@stablelib/binary/-/binary-1.0.1.tgz#c5900b94368baf00f811da5bdb1610963dfddf7f"
|
|
||||||
integrity sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==
|
|
||||||
dependencies:
|
|
||||||
"@stablelib/int" "^1.0.1"
|
|
||||||
|
|
||||||
"@stablelib/ed25519@^1.0.2":
|
|
||||||
version "1.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/@stablelib/ed25519/-/ed25519-1.0.3.tgz#f8fdeb6f77114897c887bb6a3138d659d3f35996"
|
|
||||||
integrity sha512-puIMWaX9QlRsbhxfDc5i+mNPMY+0TmQEskunY1rZEBPi1acBCVQAhnsk/1Hk50DGPtVsZtAWQg4NHGlVaO9Hqg==
|
|
||||||
dependencies:
|
|
||||||
"@stablelib/random" "^1.0.2"
|
|
||||||
"@stablelib/sha512" "^1.0.1"
|
|
||||||
"@stablelib/wipe" "^1.0.1"
|
|
||||||
|
|
||||||
"@stablelib/hash@^1.0.1":
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@stablelib/hash/-/hash-1.0.1.tgz#3c944403ff2239fad8ebb9015e33e98444058bc5"
|
|
||||||
integrity sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==
|
|
||||||
|
|
||||||
"@stablelib/int@^1.0.1":
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@stablelib/int/-/int-1.0.1.tgz#75928cc25d59d73d75ae361f02128588c15fd008"
|
|
||||||
integrity sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==
|
|
||||||
|
|
||||||
"@stablelib/random@^1.0.2":
|
|
||||||
version "1.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/@stablelib/random/-/random-1.0.2.tgz#2dece393636489bf7e19c51229dd7900eddf742c"
|
|
||||||
integrity sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==
|
|
||||||
dependencies:
|
|
||||||
"@stablelib/binary" "^1.0.1"
|
|
||||||
"@stablelib/wipe" "^1.0.1"
|
|
||||||
|
|
||||||
"@stablelib/sha512@^1.0.1":
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@stablelib/sha512/-/sha512-1.0.1.tgz#6da700c901c2c0ceacbd3ae122a38ac57c72145f"
|
|
||||||
integrity sha512-13gl/iawHV9zvDKciLo1fQ8Bgn2Pvf7OV6amaRVKiq3pjQ3UmEpXxWiAfV8tYjUpeZroBxtyrwtdooQT/i3hzw==
|
|
||||||
dependencies:
|
|
||||||
"@stablelib/binary" "^1.0.1"
|
|
||||||
"@stablelib/hash" "^1.0.1"
|
|
||||||
"@stablelib/wipe" "^1.0.1"
|
|
||||||
|
|
||||||
"@stablelib/wipe@^1.0.1":
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@stablelib/wipe/-/wipe-1.0.1.tgz#d21401f1d59ade56a62e139462a97f104ed19a36"
|
|
||||||
integrity sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==
|
|
||||||
|
|
||||||
"@surma/rollup-plugin-off-main-thread@^2.2.3":
|
"@surma/rollup-plugin-off-main-thread@^2.2.3":
|
||||||
version "2.2.3"
|
version "2.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz#ee34985952ca21558ab0d952f00298ad2190c053"
|
resolved "https://registry.yarnpkg.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz#ee34985952ca21558ab0d952f00298ad2190c053"
|
||||||
|
@ -4947,6 +4899,11 @@ electron-to-chromium@^1.4.251:
|
||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.257.tgz#895dc73c6bb58d1235dc80879ecbca0bcba96e2c"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.257.tgz#895dc73c6bb58d1235dc80879ecbca0bcba96e2c"
|
||||||
integrity sha512-C65sIwHqNnPC2ADMfse/jWTtmhZMII+x6ADI9gENzrOiI7BpxmfKFE84WkIEl5wEg+7+SfIkwChDlsd1Erju2A==
|
integrity sha512-C65sIwHqNnPC2ADMfse/jWTtmhZMII+x6ADI9gENzrOiI7BpxmfKFE84WkIEl5wEg+7+SfIkwChDlsd1Erju2A==
|
||||||
|
|
||||||
|
email-validator@^2.0.4:
|
||||||
|
version "2.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/email-validator/-/email-validator-2.0.4.tgz#b8dfaa5d0dae28f1b03c95881d904d4e40bfe7ed"
|
||||||
|
integrity sha512-gYCwo7kh5S3IDyZPLZf6hSS0MnZT8QmJFqYvbqlDZSbwdZlY6QZWxJ4i/6UhITOJ4XzyI647Bm2MXKCLqnJ4nQ==
|
||||||
|
|
||||||
emittery@^0.10.2:
|
emittery@^0.10.2:
|
||||||
version "0.10.2"
|
version "0.10.2"
|
||||||
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933"
|
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933"
|
||||||
|
@ -8722,11 +8679,6 @@ multicast-dns@^7.2.5:
|
||||||
dns-packet "^5.2.2"
|
dns-packet "^5.2.2"
|
||||||
thunky "^1.0.2"
|
thunky "^1.0.2"
|
||||||
|
|
||||||
multiformats@^9.4.2:
|
|
||||||
version "9.9.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-9.9.0.tgz#c68354e7d21037a8f1f8833c8ccd68618e8f1d37"
|
|
||||||
integrity sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==
|
|
||||||
|
|
||||||
nanoid@^3.3.1, nanoid@^3.3.4:
|
nanoid@^3.3.1, nanoid@^3.3.4:
|
||||||
version "3.3.4"
|
version "3.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
|
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
|
||||||
|
@ -9037,11 +8989,6 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
wrappy "1"
|
wrappy "1"
|
||||||
|
|
||||||
one-webcrypto@^1.0.3:
|
|
||||||
version "1.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/one-webcrypto/-/one-webcrypto-1.0.3.tgz#f951243cde29b79b6745ad14966fc598a609997c"
|
|
||||||
integrity sha512-fu9ywBVBPx0gS9K0etIROTiCkvI5S1TDjFsYFb3rC1ewFxeOqsbzq7aIMBHsYfrTHBcGXJaONXXjTl8B01cW1Q==
|
|
||||||
|
|
||||||
onetime@^2.0.0:
|
onetime@^2.0.0:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
|
resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
|
||||||
|
@ -10930,7 +10877,7 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||||
|
|
||||||
semver@^7.2.1, semver@^7.3.2, semver@^7.3.5, semver@^7.3.6, semver@^7.3.7:
|
semver@^7.2.1, semver@^7.3.2, semver@^7.3.5, semver@^7.3.7:
|
||||||
version "7.3.7"
|
version "7.3.7"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
|
||||||
integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
|
integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
|
||||||
|
@ -11904,16 +11851,6 @@ ua-parser-js@^0.7.30:
|
||||||
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6"
|
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6"
|
||||||
integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==
|
integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==
|
||||||
|
|
||||||
ucans@0.9.1:
|
|
||||||
version "0.9.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/ucans/-/ucans-0.9.1.tgz#d4ed0ed61d11ef13925512d365b26c5c9451b852"
|
|
||||||
integrity sha512-Vr2z5cy3YcPDhK9RY5VOfoqrXEml3GmZCGovFhLOIVji5PPiR/pkA2ME9jGWqLBQ1mj3494aBjxcMu4DreaAcg==
|
|
||||||
dependencies:
|
|
||||||
"@stablelib/ed25519" "^1.0.2"
|
|
||||||
one-webcrypto "^1.0.3"
|
|
||||||
semver "^7.3.6"
|
|
||||||
uint8arrays "^3.0.0"
|
|
||||||
|
|
||||||
uglify-es@^3.1.9:
|
uglify-es@^3.1.9:
|
||||||
version "3.3.9"
|
version "3.3.9"
|
||||||
resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677"
|
resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677"
|
||||||
|
@ -11922,13 +11859,6 @@ uglify-es@^3.1.9:
|
||||||
commander "~2.13.0"
|
commander "~2.13.0"
|
||||||
source-map "~0.6.1"
|
source-map "~0.6.1"
|
||||||
|
|
||||||
uint8arrays@^3.0.0:
|
|
||||||
version "3.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.1.0.tgz#8186b8eafce68f28bd29bd29d683a311778901e2"
|
|
||||||
integrity sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog==
|
|
||||||
dependencies:
|
|
||||||
multiformats "^9.4.2"
|
|
||||||
|
|
||||||
unbox-primitive@^1.0.2:
|
unbox-primitive@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
|
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
|
||||||
|
|
Loading…
Reference in New Issue