2020-07-29 19:07:13 +03:00
import * as React from "react" ;
import * as NavigationData from "~/common/navigation-data" ;
import * as Actions from "~/common/actions" ;
2020-09-12 09:13:10 +03:00
import * as Strings from "~/common/strings" ;
2020-07-29 19:07:13 +03:00
import * as State from "~/common/state" ;
import * as Credentials from "~/common/credentials" ;
2020-10-05 00:30:28 +03:00
import * as Constants from "~/common/constants" ;
2020-08-02 09:00:04 +03:00
import * as Validations from "~/common/validations" ;
2020-08-20 08:20:18 +03:00
import * as FileUtilities from "~/common/file-utilities" ;
2020-08-09 11:38:16 +03:00
import * as System from "~/components/system" ;
2020-09-12 08:54:54 +03:00
import * as Window from "~/common/window" ;
2020-10-02 07:24:10 +03:00
import * as Store from "~/common/store" ;
2020-10-27 07:41:42 +03:00
import * as Websockets from "~/common/browser-websockets" ;
2020-07-29 19:07:13 +03:00
// NOTE(jim):
// Scenes each have an ID and can be navigated to with _handleAction
import SceneDeals from "~/scenes/SceneDeals" ;
import SceneEditAccount from "~/scenes/SceneEditAccount" ;
import SceneFile from "~/scenes/SceneFile" ;
import SceneFilesFolder from "~/scenes/SceneFilesFolder" ;
import SceneHome from "~/scenes/SceneHome" ;
import SceneSettings from "~/scenes/SceneSettings" ;
import SceneWallet from "~/scenes/SceneWallet" ;
import SceneSlates from "~/scenes/SceneSlates" ;
import SceneLocalData from "~/scenes/SceneLocalData" ;
import SceneSettingsDeveloper from "~/scenes/SceneSettingsDeveloper" ;
import SceneSignIn from "~/scenes/SceneSignIn" ;
import SceneSlate from "~/scenes/SceneSlate" ;
2020-08-08 03:17:54 +03:00
import SceneActivity from "~/scenes/SceneActivity" ;
2020-08-18 22:41:41 +03:00
import SceneDirectory from "~/scenes/SceneDirectory" ;
2020-08-31 21:19:46 +03:00
import SceneProfile from "~/scenes/SceneProfile" ;
2020-09-03 10:33:43 +03:00
import SceneSentinel from "~/scenes/SceneSentinel" ;
2020-09-03 06:26:56 +03:00
import ScenePublicProfile from "~/scenes/ScenePublicProfile" ;
import ScenePublicSlate from "~/scenes/ScenePublicSlate" ;
2020-09-10 02:52:45 +03:00
import SceneArchive from "~/scenes/SceneArchive" ;
2020-09-23 01:01:36 +03:00
import SceneMakeFilecoinDeal from "~/scenes/SceneMakeFilecoinDeal" ;
2020-09-25 08:14:19 +03:00
import SceneEncryptedData from "~/scenes/SceneEncryptedData" ;
2020-09-27 19:38:20 +03:00
import SceneMiners from "~/scenes/SceneMiners" ;
2020-10-19 21:52:13 +03:00
import SceneTara from "~/scenes/SceneTara" ;
2020-07-29 19:07:13 +03:00
// NOTE(jim):
// Sidebars each have a decorator and can be shown to with _handleAction
import SidebarCreateSlate from "~/components/sidebars/SidebarCreateSlate" ;
import SidebarCreateWalletAddress from "~/components/sidebars/SidebarCreateWalletAddress" ;
import SidebarWalletSendFunds from "~/components/sidebars/SidebarWalletSendFunds" ;
import SidebarFileStorageDeal from "~/components/sidebars/SidebarFileStorageDeal" ;
import SidebarAddFileToBucket from "~/components/sidebars/SidebarAddFileToBucket" ;
2020-09-23 23:52:00 +03:00
import SidebarAddFileToSlate from "~/components/sidebars/SidebarAddFileToSlate" ;
2020-08-02 10:55:55 +03:00
import SidebarDragDropNotice from "~/components/sidebars/SidebarDragDropNotice" ;
2020-08-09 11:08:46 +03:00
import SidebarSingleSlateSettings from "~/components/sidebars/SidebarSingleSlateSettings" ;
2020-08-28 09:57:04 +03:00
import SidebarFilecoinArchive from "~/components/sidebars/SidebarFilecoinArchive" ;
2020-09-17 02:26:15 +03:00
import SidebarHelp from "~/components/sidebars/SidebarHelp" ;
2020-07-29 19:07:13 +03:00
// NOTE(jim):
// Core components to the application structure.
import ApplicationNavigation from "~/components/core/ApplicationNavigation" ;
import ApplicationHeader from "~/components/core/ApplicationHeader" ;
import ApplicationLayout from "~/components/core/ApplicationLayout" ;
import WebsitePrototypeWrapper from "~/components/core/WebsitePrototypeWrapper" ;
import Cookies from "universal-cookie" ;
2020-10-27 07:14:13 +03:00
import { OnboardingModal } from "~/components/core/OnboardingModal" ;
2020-09-03 09:00:02 +03:00
import { dispatchCustomEvent } from "~/common/custom-events" ;
2020-10-24 00:28:53 +03:00
import { Alert } from "~/components/core/Alert" ;
2020-10-29 20:43:04 +03:00
import { announcements } from "~/components/core/OnboardingModal" ;
2020-09-03 09:00:02 +03:00
2020-07-29 19:07:13 +03:00
const cookies = new Cookies ( ) ;
2020-08-14 12:17:19 +03:00
const SIDEBARS = {
2020-08-28 09:57:04 +03:00
SIDEBAR _FILECOIN _ARCHIVE : < SidebarFilecoinArchive / > ,
2020-08-14 12:17:19 +03:00
SIDEBAR _FILE _STORAGE _DEAL : < SidebarFileStorageDeal / > ,
SIDEBAR _WALLET _SEND _FUNDS : < SidebarWalletSendFunds / > ,
SIDEBAR _CREATE _WALLET _ADDRESS : < SidebarCreateWalletAddress / > ,
SIDEBAR _ADD _FILE _TO _BUCKET : < SidebarAddFileToBucket / > ,
2020-09-23 23:52:00 +03:00
SIDEBAR _ADD _FILE _TO _SLATE : < SidebarAddFileToSlate / > ,
2020-08-14 12:17:19 +03:00
SIDEBAR _CREATE _SLATE : < SidebarCreateSlate / > ,
SIDEBAR _DRAG _DROP _NOTICE : < SidebarDragDropNotice / > ,
SIDEBAR _SINGLE _SLATE _SETTINGS : < SidebarSingleSlateSettings / > ,
2020-09-17 02:26:15 +03:00
SIDEBAR _HELP : < SidebarHelp / > ,
2020-08-14 12:17:19 +03:00
} ;
const SCENES = {
HOME : < SceneHome / > ,
2020-08-31 21:19:46 +03:00
DIRECTORY : < SceneDirectory / > ,
2020-09-03 06:26:56 +03:00
PUBLIC _PROFILE : < ScenePublicProfile / > ,
2020-09-04 01:42:08 +03:00
PROFILE : < SceneProfile / > ,
2020-08-14 12:17:19 +03:00
WALLET : < SceneWallet / > ,
FOLDER : < SceneFilesFolder / > ,
FILE : < SceneFile / > ,
2020-09-04 01:42:08 +03:00
PUBLIC _SLATE : < ScenePublicSlate / > ,
2020-08-14 12:17:19 +03:00
SLATE : < SceneSlate / > ,
DEALS : < SceneDeals / > ,
SETTINGS : < SceneSettings / > ,
SETTINGS _DEVELOPER : < SceneSettingsDeveloper / > ,
EDIT _ACCOUNT : < SceneEditAccount / > ,
SLATES : < SceneSlates / > ,
LOCAL _DATA : < SceneLocalData / > ,
2020-09-03 10:33:43 +03:00
NETWORK : < SceneSentinel / > ,
2020-08-18 22:41:41 +03:00
DIRECTORY : < SceneDirectory / > ,
2020-09-09 20:56:35 +03:00
FILECOIN : < SceneArchive / > ,
2020-09-23 01:01:36 +03:00
MAKE _DEAL : < SceneMakeFilecoinDeal / > ,
2020-09-25 08:14:19 +03:00
ENCRYPTED : < SceneEncryptedData / > ,
2020-09-27 19:38:20 +03:00
MINERS : < SceneMiners / > ,
2020-10-19 21:52:13 +03:00
TARA : < SceneTara / > ,
2020-08-14 12:17:19 +03:00
} ;
2020-10-26 04:26:30 +03:00
let mounted ;
2020-07-29 19:07:13 +03:00
export default class ApplicationPage extends React . Component {
2020-08-31 21:19:46 +03:00
_body ;
2020-07-29 19:07:13 +03:00
state = {
2020-08-25 09:46:02 +03:00
selected : { } ,
viewer : this . props . viewer ,
2020-08-18 22:28:33 +03:00
history : [ { id : "V1_NAVIGATION_HOME" , scrollTop : 0 , data : null } ] ,
2020-07-29 19:07:13 +03:00
currentIndex : 0 ,
data : null ,
sidebar : null ,
sidebarLoading : false ,
2020-08-03 00:09:55 +03:00
online : null ,
2020-09-27 00:15:37 +03:00
sidebar : null ,
2020-10-23 06:55:24 +03:00
mobile : this . props . mobile ,
2020-07-29 19:07:13 +03:00
} ;
async componentDidMount ( ) {
2020-10-26 04:26:30 +03:00
if ( mounted ) {
return false ;
2020-10-26 01:56:57 +03:00
}
2020-10-26 04:26:30 +03:00
mounted = true ;
2020-10-26 01:56:57 +03:00
2020-07-29 19:07:13 +03:00
window . addEventListener ( "dragenter" , this . _handleDragEnter ) ;
window . addEventListener ( "dragleave" , this . _handleDragLeave ) ;
window . addEventListener ( "dragover" , this . _handleDragOver ) ;
window . addEventListener ( "drop" , this . _handleDrop ) ;
2020-08-03 00:09:55 +03:00
window . addEventListener ( "online" , this . _handleOnlineStatus ) ;
window . addEventListener ( "offline" , this . _handleOnlineStatus ) ;
2020-10-23 06:55:24 +03:00
window . addEventListener ( "resize" , this . _handleWindowResize ) ;
2020-09-12 08:54:54 +03:00
const id = Window . getQueryParameterByName ( "scene" ) ;
2020-10-26 04:26:30 +03:00
let wsclient = Websockets . getClient ( ) ;
if ( wsclient ) {
await Websockets . deleteClient ( ) ;
wsclient = null ;
}
2020-10-27 22:01:32 +03:00
if ( this . state . viewer ) {
wsclient = this . _handleSetupWebsocket ( ) ;
if ( ! wsclient ) {
dispatchCustomEvent ( {
name : "create-alert" ,
detail : {
alert : {
message :
"We cannot connect to our live update server. You may have to refresh to see updates." ,
} ,
} ,
} ) ;
}
2020-10-26 04:26:30 +03:00
}
2020-09-12 09:13:10 +03:00
if ( ! Strings . isEmpty ( id ) && this . state . viewer ) {
2020-09-12 08:54:54 +03:00
return this . _handleNavigateTo ( { id } ) ;
}
2020-07-29 19:07:13 +03:00
}
componentWillUnmount ( ) {
window . removeEventListener ( "dragenter" , this . _handleDragEnter ) ;
window . removeEventListener ( "dragleave" , this . _handleDragLeave ) ;
window . removeEventListener ( "dragover" , this . _handleDragOver ) ;
window . removeEventListener ( "drop" , this . _handleDrop ) ;
2020-10-23 06:55:24 +03:00
window . removeEventListener ( "resize" , this . _handleWindowResize ) ;
2020-10-26 04:26:30 +03:00
mounted = false ;
let wsclient = Websockets . getClient ( ) ;
if ( wsclient ) {
Websockets . deleteClient ( ) ;
}
2020-07-29 19:07:13 +03:00
}
2020-10-31 02:12:20 +03:00
//make this a function that can handle different types of inputs and updates state accordingly (rather than ahving a bunch of different functions for each type)
2020-10-27 07:41:42 +03:00
_handleUpdateViewer = ( newViewerState ) => {
2020-10-31 02:12:20 +03:00
console . log ( "update viewer" ) ;
2020-10-27 07:41:42 +03:00
console . log ( { newViewerState } ) ;
if ( this . state . viewer && newViewerState . id && newViewerState . id === this . state . viewer . id ) {
this . setState ( {
viewer : { ... this . state . viewer , ... newViewerState , type : "VIEWER" } ,
} ) ;
}
} ;
2020-10-26 04:26:30 +03:00
_handleSetupWebsocket = ( ) => {
if ( this . props . resources && ! Strings . isEmpty ( this . props . resources . pubsub ) ) {
if ( ! this . state . viewer ) {
console . log ( "WEBSOCKET: NOT AUTHENTICATED" ) ;
return null ;
}
return Websockets . init ( {
resource : this . props . resources . pubsub ,
viewer : this . state . viewer ,
2020-10-27 07:41:42 +03:00
onUpdate : this . _handleUpdateViewer ,
2020-10-26 04:26:30 +03:00
} ) ;
}
return null ;
} ;
2020-10-23 06:55:24 +03:00
_handleWindowResize = ( ) => {
const { width } = Window . getViewportSize ( ) ;
// (1) is Window.isMobileBrowser checks, that one holds.
// (2) then if the viewport is smaller than the width
let mobile = width > Constants . sizes . mobile ? this . props . mobile : true ;
// only change if necessary.
if ( this . state . mobile !== mobile ) {
console . log ( "changing to mobile?" , mobile ) ;
this . setState ( { mobile } ) ;
}
} ;
2020-08-03 00:09:55 +03:00
_handleOnlineStatus = async ( ) => {
2020-09-12 01:25:33 +03:00
if ( navigator . onLine ) {
dispatchCustomEvent ( {
name : "create-alert" ,
detail : { alert : { message : "Back online!" , status : "INFO" } } ,
} ) ;
} else {
dispatchCustomEvent ( {
name : "create-alert" ,
detail : { alert : { message : "Offline. Trying to reconnect" } } ,
} ) ;
}
2020-08-03 00:09:55 +03:00
this . setState ( { online : navigator . onLine } ) ;
} ;
2020-09-21 00:34:31 +03:00
_handleDrop = async ( e ) => {
2020-09-25 06:16:10 +03:00
this . _handleDismissSidebar ( ) ;
2020-09-21 00:34:31 +03:00
// NOTE(jim): If this is true, then drag and drop came from a slate object.
const data = e . dataTransfer . getData ( "slate-object-drag-data" ) ;
if ( data ) {
return ;
}
e . preventDefault ( ) ;
// TODO(jim): Refactor later
const navigation = NavigationData . generate ( this . state . viewer ) ;
const next = this . state . history [ this . state . currentIndex ] ;
const current = NavigationData . getCurrentById ( navigation , next . id ) ;
let slate = null ;
if ( current . target && current . target . slateId ) {
slate = { id : current . target . slateId } ;
}
const files = [ ] ;
let fileLoading = { } ;
2020-09-25 06:16:10 +03:00
// let sidebarOpen = false;
2020-09-21 00:34:31 +03:00
if ( e . dataTransfer . items && e . dataTransfer . items . length ) {
for ( var i = 0 ; i < e . dataTransfer . items . length ; i ++ ) {
if ( e . dataTransfer . items [ i ] . kind === "file" ) {
var file = e . dataTransfer . items [ i ] . getAsFile ( ) ;
2020-09-25 06:16:10 +03:00
// if (!sidebarOpen) {
// this._handleAction({
// type: "SIDEBAR",
// value: "SIDEBAR_ADD_FILE_TO_BUCKET",
// data: slate,
// });
// sidebarOpen = true;
// }
2020-09-20 21:31:08 +03:00
2020-09-21 00:34:31 +03:00
files . push ( file ) ;
fileLoading [ ` ${ file . lastModified } - ${ file . name } ` ] = {
name : file . name ,
loaded : 0 ,
total : file . size ,
} ;
}
}
}
if ( ! files . length ) {
2020-09-20 21:31:08 +03:00
dispatchCustomEvent ( {
name : "create-alert" ,
detail : {
alert : {
2020-09-21 00:34:31 +03:00
message : "File type not supported. Please try a different file" ,
2020-09-20 21:31:08 +03:00
} ,
} ,
} ) ;
2020-09-21 00:34:31 +03:00
return ;
2020-09-20 21:31:08 +03:00
}
2020-09-21 00:34:31 +03:00
// NOTE(jim): Stages each file.
this . _handleRegisterFileLoading ( { fileLoading } ) ;
2020-09-25 06:16:10 +03:00
this . _handleUpload ( { files , slate , keys : Object . keys ( fileLoading ) } ) ;
2020-09-20 21:31:08 +03:00
} ;
2020-09-25 09:42:21 +03:00
_handleUploadFiles = async ( { files , slate } ) => {
2020-09-20 21:31:08 +03:00
let toUpload = [ ] ;
let fileLoading = { } ;
let someFailed = false ;
for ( let i = 0 ; i < files . length ; i ++ ) {
let file = files [ i ] ;
if ( ! file ) {
someFailed = true ;
continue ;
}
toUpload . push ( file ) ;
fileLoading [ ` ${ file . lastModified } - ${ file . name } ` ] = {
name : file . name ,
loaded : 0 ,
total : file . size ,
} ;
}
if ( ! toUpload . length ) {
dispatchCustomEvent ( {
name : "create-alert" ,
detail : {
alert : { message : "We could not find any files to upload." } ,
} ,
} ) ;
return false ;
}
2020-09-20 23:38:27 +03:00
if ( someFailed ) {
dispatchCustomEvent ( {
name : "create-alert" ,
detail : {
alert : { message : "Some of your files could not be uploaded" } ,
} ,
} ) ;
}
2020-09-20 21:31:08 +03:00
this . _handleRegisterFileLoading ( { fileLoading } ) ;
2020-09-25 06:16:10 +03:00
this . _handleUpload ( {
files : toUpload ,
slate ,
keys : Object . keys ( fileLoading ) ,
} ) ;
2020-09-21 00:34:31 +03:00
} ;
2020-09-25 09:42:21 +03:00
_handleUpload = async ( { files , slate , keys } ) => {
2020-09-23 04:10:27 +03:00
if ( ! files || ! files . length ) {
return null ;
}
const resolvedFiles = [ ] ;
for ( let i = 0 ; i < files . length ; i ++ ) {
2020-10-02 07:24:10 +03:00
if ( Store . checkCancelled ( ` ${ files [ i ] . lastModified } - ${ files [ i ] . name } ` ) ) {
continue ;
}
2020-10-10 08:12:28 +03:00
// NOTE(jim): With so many failures, probably good to wait a few seconds.
await Window . delay ( 3000 ) ;
// NOTE(jim): Sends XHR request.
let response = null ;
try {
response = await FileUtilities . upload ( {
file : files [ i ] ,
context : this ,
2020-10-23 13:34:31 +03:00
routes : this . props . resources ,
2020-10-10 08:12:28 +03:00
} ) ;
} catch ( e ) {
console . log ( e ) ;
}
// NOTE(jim): We probably don't want to keep the responses for failed attempt.
if ( ! response || response . error ) {
continue ;
}
2020-09-23 04:10:27 +03:00
2020-10-02 07:24:10 +03:00
if ( response ) {
resolvedFiles . push ( response ) ;
}
2020-09-23 04:10:27 +03:00
}
2020-10-10 08:12:28 +03:00
if ( ! resolvedFiles . length ) {
this . setState ( { fileLoading : { } } ) ;
return null ;
}
2020-09-25 06:16:10 +03:00
let responses = await Promise . allSettled ( resolvedFiles ) ;
2020-09-25 09:42:21 +03:00
2020-09-25 06:16:10 +03:00
let succeeded = responses
. filter ( ( res ) => {
return res . status === "fulfilled" && res . value && ! res . value . error ;
2020-09-22 01:21:39 +03:00
} )
2020-09-25 06:16:10 +03:00
. map ( ( res ) => res . value ) ;
2020-09-27 00:15:37 +03:00
if ( slate && slate . id ) {
2020-09-25 06:16:10 +03:00
await FileUtilities . uploadToSlate ( { responses : succeeded , slate } ) ;
}
2020-09-25 09:42:21 +03:00
2020-09-25 06:16:10 +03:00
let processResponse = await Actions . processPendingFiles ( ) ;
if ( ! processResponse ) {
dispatchCustomEvent ( {
name : "create-alert" ,
detail : {
alert : {
2020-10-19 21:52:13 +03:00
message : "We encountered issues updating your uploaded files. Please try again" ,
2020-09-25 06:16:10 +03:00
} ,
} ,
} ) ;
return ;
}
2020-09-25 09:42:21 +03:00
2020-09-25 06:16:10 +03:00
if ( processResponse . error ) {
dispatchCustomEvent ( {
name : "create-alert" ,
detail : {
alert : {
decorator : processResponse . decorator ,
} ,
} ,
} ) ;
return ;
}
2020-09-25 09:42:21 +03:00
2020-10-31 02:12:20 +03:00
this . setState ( { sidebar : null } ) ;
2020-09-22 01:21:39 +03:00
2020-09-25 06:16:10 +03:00
if ( ! slate ) {
const { added , skipped } = processResponse . data ;
2020-10-31 02:12:20 +03:00
let message = Strings . formatAsUploadMessage ( added , skipped ) ;
2020-09-25 06:16:10 +03:00
dispatchCustomEvent ( {
name : "create-alert" ,
detail : {
alert : { message , status : ! added ? null : "INFO" } ,
} ,
2020-09-20 21:31:08 +03:00
} ) ;
2020-09-25 06:16:10 +03:00
}
2020-09-25 09:42:21 +03:00
2020-09-25 06:16:10 +03:00
this . _handleRegisterLoadingFinished ( { keys } ) ;
2020-09-25 09:42:21 +03:00
return null ;
2020-08-20 08:20:18 +03:00
} ;
_handleRegisterFileLoading = ( { fileLoading } ) => {
2020-09-11 02:06:06 +03:00
if ( this . state . fileLoading ) {
return this . setState ( {
fileLoading : { ... this . state . fileLoading , ... fileLoading } ,
} ) ;
}
2020-08-16 01:38:09 +03:00
return this . setState ( {
fileLoading ,
} ) ;
} ;
2020-10-02 07:24:10 +03:00
_handleRegisterFileCancelled = ( { key } ) => {
let fileLoading = this . state . fileLoading ;
fileLoading [ key ] . cancelled = true ;
this . setState ( { fileLoading } ) ;
} ;
2020-09-25 06:16:10 +03:00
_handleRegisterLoadingFinished = ( { keys } ) => {
let fileLoading = this . state . fileLoading ;
for ( let key of keys ) {
delete fileLoading [ key ] ;
}
this . setState ( { fileLoading } ) ;
} ;
2020-07-29 19:07:13 +03:00
_handleDragEnter = ( e ) => {
2020-08-22 12:32:40 +03:00
e . preventDefault ( ) ;
2020-08-02 10:55:55 +03:00
if ( this . state . sidebar ) {
return ;
}
2020-08-22 12:32:40 +03:00
// NOTE(jim): Only allow the sidebar to show with file drag and drop.
2020-08-25 09:46:02 +03:00
if (
e . dataTransfer . items &&
e . dataTransfer . items . length &&
e . dataTransfer . items [ 0 ] . kind !== "file"
) {
2020-08-22 12:32:40 +03:00
return ;
}
2020-08-02 10:55:55 +03:00
this . _handleAction ( {
type : "SIDEBAR" ,
value : "SIDEBAR_DRAG_DROP_NOTICE" ,
} ) ;
2020-07-29 19:07:13 +03:00
} ;
_handleDragLeave = ( e ) => {
2020-08-02 10:55:55 +03:00
e . preventDefault ( ) ;
2020-07-29 19:07:13 +03:00
} ;
_handleDragOver = ( e ) => {
e . preventDefault ( ) ;
} ;
_handleSidebarLoading = ( sidebarLoading ) => this . setState ( { sidebarLoading } ) ;
2020-10-31 02:12:20 +03:00
//change the naem to hydrate. and use this only upon initial sign in (should be the only time you need it)
2020-08-15 05:08:17 +03:00
rehydrate = async ( options ) => {
2020-07-29 19:07:13 +03:00
const response = await Actions . hydrateAuthenticatedUser ( ) ;
if ( ! response || response . error ) {
2020-09-12 01:25:33 +03:00
dispatchCustomEvent ( {
name : "create-alert" ,
detail : {
alert : {
message : "We encountered issues while refreshing. Please try again" ,
} ,
} ,
} ) ;
2020-07-29 19:07:13 +03:00
return null ;
}
2020-08-24 08:59:37 +03:00
console . log ( "REHYDRATION CALL" , response ) ;
2020-08-15 05:08:17 +03:00
const updates = {
2020-09-03 09:00:02 +03:00
viewer : JSON . parse ( JSON . stringify ( response . data ) ) ,
2020-08-15 05:08:17 +03:00
} ;
if ( options && options . resetFiles ) {
2020-08-15 05:18:55 +03:00
updates . sidebar = null ;
2020-08-15 05:08:17 +03:00
}
this . setState ( updates ) ;
2020-07-29 19:07:13 +03:00
2020-08-31 21:19:46 +03:00
return response ;
2020-07-29 19:07:13 +03:00
} ;
_handleSubmit = async ( data ) => {
let response ;
2020-08-09 11:08:46 +03:00
2020-07-29 19:07:13 +03:00
if ( data . type === "CREATE_SLATE" ) {
response = await Actions . createSlate ( {
name : data . name ,
2020-09-14 08:22:19 +03:00
public : data . public ,
body : data . body ,
2020-07-29 19:07:13 +03:00
} ) ;
}
if ( data . type === "CREATE_WALLET_ADDRESS" ) {
response = await Actions . updateViewer ( {
type : "CREATE_FILECOIN_ADDRESS" ,
address : {
name : data . name ,
type : data . wallet _type ,
makeDefault : data . makeDefault ,
} ,
} ) ;
}
if ( data . type === "SEND_WALLET_ADDRESS_FILECOIN" ) {
response = await Actions . sendFilecoin ( {
source : data . source ,
target : data . target ,
amount : data . amount ,
} ) ;
}
this . _handleDismissSidebar ( ) ;
return response ;
} ;
_handleDeleteYourself = async ( ) => {
2020-09-12 01:25:33 +03:00
// TODO(jim): Put this somewhere better for messages.
2020-10-19 21:52:13 +03:00
const message = "Do you really want to delete your account? It will be permanently removed" ;
2020-07-29 19:07:13 +03:00
if ( ! window . confirm ( message ) ) {
return false ;
}
let response = await Actions . deleteViewer ( ) ;
2020-09-13 05:59:47 +03:00
if ( ! response || response . error ) {
dispatchCustomEvent ( {
name : "create-alert" ,
detail : {
alert : {
2020-10-19 21:52:13 +03:00
message : "We're having trouble connecting right now. Please try again later" ,
2020-09-13 05:59:47 +03:00
} ,
} ,
} ) ;
return response ;
}
2020-07-29 19:07:13 +03:00
await this . _handleSignOut ( ) ;
2020-09-13 05:59:47 +03:00
2020-10-26 04:26:30 +03:00
let wsclient = Websockets . getClient ( ) ;
if ( wsclient ) {
await Websockets . deleteClient ( ) ;
wsclient = null ;
}
2020-09-13 05:59:47 +03:00
return response ;
2020-07-29 19:07:13 +03:00
} ;
2020-09-15 05:58:23 +03:00
_handleCreateUser = async ( state ) => {
// NOTE(jim): Acts as our existing username exists check.
// If the user exists, move on the sign in anyways.
let response = await Actions . createUser ( state ) ;
console . log ( "CREATE_USER" , response ) ;
if ( ! response || response . error ) {
return response ;
}
2020-10-27 07:14:13 +03:00
return this . _handleAuthenticate ( state , true ) ;
2020-09-15 05:58:23 +03:00
} ;
2020-10-27 07:14:13 +03:00
_handleAuthenticate = async ( state , newAccount ) => {
2020-07-29 19:07:13 +03:00
// NOTE(jim): Kills existing session cookie if there is one.
const jwt = cookies . get ( Credentials . session . key ) ;
if ( jwt ) {
cookies . remove ( Credentials . session . key ) ;
}
2020-09-15 05:58:23 +03:00
let response = await Actions . signIn ( state ) ;
2020-09-13 01:08:36 +03:00
if ( ! response || response . error ) {
return response ;
2020-07-29 19:07:13 +03:00
}
if ( response . token ) {
// NOTE(jim):
// + One week.
// + Only requests to the same site.
// + Not using sessionStorage so the cookie doesn't leave when the browser dies.
cookies . set ( Credentials . session . key , response . token , true , {
path : "/" ,
maxAge : 3600 * 24 * 7 ,
sameSite : "strict" ,
} ) ;
}
2020-09-15 05:58:23 +03:00
await this . rehydrate ( ) ;
2020-10-26 04:26:30 +03:00
let wsclient = Websockets . getClient ( ) ;
if ( wsclient ) {
await Websockets . deleteClient ( ) ;
wsclient = null ;
}
wsclient = this . _handleSetupWebsocket ( ) ;
if ( ! wsclient ) {
2020-10-27 22:01:32 +03:00
dispatchCustomEvent ( {
name : "create-alert" ,
detail : {
alert : {
message :
"We cannot connect to our live update server. You may have to refresh to see updates." ,
} ,
} ,
} ) ;
2020-10-26 04:26:30 +03:00
}
2020-10-27 07:14:13 +03:00
this . _handleAction ( { type : "NAVIGATE" , value : "V1_NAVIGATION_HOME" } ) ;
2020-10-29 20:43:04 +03:00
let unseenAnnouncements = [ ] ;
for ( let feature of announcements ) {
2020-11-04 00:43:11 +03:00
if ( ! Object . keys ( this . state . viewer . onboarding ) . includes ( feature ) ) {
unseenAnnouncements . push ( feature ) ;
2020-10-29 20:43:04 +03:00
}
}
if ( newAccount || unseenAnnouncements . length ) {
2020-10-27 07:14:13 +03:00
dispatchCustomEvent ( {
name : "create-modal" ,
detail : {
2020-10-29 20:43:04 +03:00
modal : (
< OnboardingModal
2020-11-04 00:43:11 +03:00
onAction = { this . _handleAction }
2020-10-29 20:43:04 +03:00
viewer = { this . state . viewer }
newAccount = { newAccount }
unseenAnnouncements = { unseenAnnouncements }
/ >
) ,
2020-10-27 07:14:13 +03:00
noBoundary : true ,
} ,
} ) ;
}
2020-09-15 05:58:23 +03:00
return response ;
2020-07-29 19:07:13 +03:00
} ;
2020-10-26 04:26:30 +03:00
_handleSignOut = async ( ) => {
let wsclient = Websockets . getClient ( ) ;
if ( wsclient ) {
await Websockets . deleteClient ( ) ;
wsclient = null ;
}
2020-07-29 19:07:13 +03:00
const jwt = cookies . get ( Credentials . session . key ) ;
if ( jwt ) {
cookies . remove ( Credentials . session . key ) ;
window . location . reload ( ) ;
}
} ;
_handleViewerChange = ( e ) => {
this . setState ( {
viewer : { ... this . state . viewer , [ e . target . name ] : e . target . value } ,
} ) ;
} ;
_handleSelectedChange = ( e ) => {
this . setState ( {
selected : { ... this . state . selected , [ e . target . name ] : e . target . value } ,
} ) ;
} ;
_handleDismissSidebar = ( ) => {
2020-08-31 21:19:46 +03:00
this . setState ( { sidebar : null , sidebarLoading : false , sidebarData : null } ) ;
2020-07-29 19:07:13 +03:00
} ;
_handleAction = ( options ) => {
if ( options . type === "NAVIGATE" ) {
2020-08-31 21:19:46 +03:00
// NOTE(martina): The `scene` property is only necessary when you need to display a component different from the one corresponding to the tab it appears in
// + e.g. to display <SceneProfile/> while on the Home tab
// + `scene` should be the decorator of the component you want displayed
return this . _handleNavigateTo (
{ id : options . value , scene : options . scene } ,
2020-10-02 02:44:22 +03:00
options . data ,
options . redirect
2020-08-31 21:19:46 +03:00
) ;
2020-07-29 19:07:13 +03:00
}
if ( options . type === "NEW_WINDOW" ) {
return window . open ( options . value ) ;
}
if ( options . type === "ACTION" ) {
2020-09-12 01:25:33 +03:00
dispatchCustomEvent ( {
name : "create-alert" ,
detail : { alert : { message : JSON . stringify ( options ) , status : "INFO" } } ,
} ) ;
2020-07-29 19:07:13 +03:00
}
if ( options . type === "DOWNLOAD" ) {
2020-09-12 01:25:33 +03:00
dispatchCustomEvent ( {
name : "create-alert" ,
detail : { alert : { message : JSON . stringify ( options ) , status : "INFO" } } ,
} ) ;
2020-07-29 19:07:13 +03:00
}
if ( options . type === "SIDEBAR" ) {
return this . setState ( {
2020-08-14 12:17:19 +03:00
sidebar : SIDEBARS [ options . value ] ,
2020-08-31 21:19:46 +03:00
sidebarData : options . data ,
2020-07-29 19:07:13 +03:00
} ) ;
}
2020-10-02 07:24:10 +03:00
if ( options . type === "REGISTER_FILE_CANCELLED" ) {
return this . _handleRegisterFileCancelled ( { key : options . value } ) ;
}
2020-09-13 01:08:36 +03:00
return alert ( JSON . stringify ( options ) ) ;
2020-07-29 19:07:13 +03:00
} ;
2020-10-02 02:44:22 +03:00
_handleNavigateTo = ( next , data = null , redirect = false ) => {
2020-09-12 08:54:54 +03:00
window . history . replaceState ( { ... next } , "Slate" , ` ?scene= ${ next . id } ` ) ;
2020-10-02 02:44:22 +03:00
if ( redirect ) {
const adjustedArray = [ ... this . state . history ] ;
adjustedArray . length = this . state . currentIndex ;
return this . setState ( {
history : [ ... adjustedArray , next ] ,
data ,
sidebar : null ,
} ) ;
}
2020-09-12 08:54:54 +03:00
2020-09-08 09:05:16 +03:00
let body = document . documentElement || document . body ;
2020-09-12 08:54:54 +03:00
this . state . history [ this . state . currentIndex ] . scrollTop = body . scrollTop ;
this . state . history [ this . state . currentIndex ] . data = this . state . data ;
2020-07-29 19:07:13 +03:00
if ( this . state . currentIndex !== this . state . history . length - 1 ) {
const adjustedArray = [ ... this . state . history ] ;
adjustedArray . length = this . state . currentIndex + 1 ;
return this . setState (
{
history : [ ... adjustedArray , next ] ,
currentIndex : this . state . currentIndex + 1 ,
data ,
sidebar : null ,
} ,
2020-08-31 21:19:46 +03:00
( ) => body . scrollTo ( 0 , 0 )
2020-07-29 19:07:13 +03:00
) ;
}
this . setState (
{
history : [ ... this . state . history , next ] ,
currentIndex : this . state . currentIndex + 1 ,
data ,
sidebar : null ,
} ,
2020-08-31 21:19:46 +03:00
( ) => body . scrollTo ( 0 , 0 )
2020-07-29 19:07:13 +03:00
) ;
} ;
_handleBack = ( ) => {
2020-09-08 09:05:16 +03:00
let body = document . documentElement || document . body ;
2020-08-31 21:19:46 +03:00
this . state . history [ this . state . currentIndex ] . scrollTop = body . scrollTop ;
2020-09-12 08:54:54 +03:00
this . state . history [ this . state . currentIndex ] . data = this . state . data ;
2020-07-29 19:07:13 +03:00
const next = this . state . history [ this . state . currentIndex - 1 ] ;
2020-09-12 08:54:54 +03:00
window . history . replaceState ( { ... next } , "Slate" , ` ?scene= ${ next . id } ` ) ;
2020-07-29 19:07:13 +03:00
this . setState (
{
currentIndex : this . state . currentIndex - 1 ,
sidebar : null ,
data : { ... next . data } ,
} ,
( ) => {
console . log ( { next } ) ;
2020-08-31 21:19:46 +03:00
body . scrollTo ( 0 , next . scrollTop ) ;
2020-07-29 19:07:13 +03:00
}
) ;
} ;
_handleForward = ( ) => {
2020-09-08 09:05:16 +03:00
let body = document . documentElement || document . body ;
2020-08-31 21:19:46 +03:00
this . state . history [ this . state . currentIndex ] . scrollTop = body . scrollTop ;
2020-07-29 19:07:13 +03:00
const next = this . state . history [ this . state . currentIndex + 1 ] ;
2020-09-12 08:54:54 +03:00
window . history . replaceState ( { ... next } , "Slate" , ` ?scene= ${ next . id } ` ) ;
2020-07-29 19:07:13 +03:00
this . setState (
{
currentIndex : this . state . currentIndex + 1 ,
sidebar : null ,
data : { ... next . data } ,
} ,
( ) => {
console . log ( { next } ) ;
2020-08-31 21:19:46 +03:00
body . scrollTo ( 0 , next . scrollTop ) ;
2020-07-29 19:07:13 +03:00
}
) ;
} ;
render ( ) {
2020-10-29 20:43:04 +03:00
console . log ( this . state . viewer ) ;
2020-07-29 19:07:13 +03:00
// NOTE(jim): Not authenticated.
if ( ! this . state . viewer ) {
return (
< WebsitePrototypeWrapper
title = "Slate: sign in"
description = "Sign in to your Slate account to manage your assets."
2020-09-08 09:05:16 +03:00
url = "https://slate.host/_"
>
2020-10-26 05:09:29 +03:00
< Alert noWarning / >
2020-08-25 09:46:02 +03:00
< SceneSignIn
2020-09-15 05:58:23 +03:00
onCreateUser = { this . _handleCreateUser }
2020-08-25 09:46:02 +03:00
onAuthenticate = { this . _handleAuthenticate }
2020-10-01 03:41:53 +03:00
onAction = { this . _handleAction }
2020-08-25 09:46:02 +03:00
/ >
2020-07-29 19:07:13 +03:00
< / W e b s i t e P r o t o t y p e W r a p p e r >
) ;
}
// NOTE(jim): Authenticated.
const navigation = NavigationData . generate ( this . state . viewer ) ;
const next = this . state . history [ this . state . currentIndex ] ;
const current = NavigationData . getCurrentById ( navigation , next . id ) ;
2020-10-23 20:41:22 +03:00
// NOTE(jim): Only happens during a bad query parameter.
if ( ! current . target ) {
window . location . replace ( "/_" ) ;
return null ;
}
2020-07-29 19:07:13 +03:00
const navigationElement = (
< ApplicationNavigation
viewer = { this . state . viewer }
activeId = { current . target . id }
activeIds = { current . activeIds }
navigation = { navigation }
onAction = { this . _handleAction }
2020-08-08 03:10:28 +03:00
onSignOut = { this . _handleSignOut }
2020-10-23 06:55:24 +03:00
mobile = { this . state . mobile }
2020-07-29 19:07:13 +03:00
/ >
) ;
2020-08-10 13:18:43 +03:00
let headerElement = (
2020-07-29 19:07:13 +03:00
< ApplicationHeader
viewer = { this . state . viewer }
pageTitle = { current . target . pageTitle }
currentIndex = { this . state . currentIndex }
2020-08-20 08:45:43 +03:00
history = { this . state . history }
2020-08-25 02:24:29 +03:00
onAction = { this . _handleAction }
2020-07-29 19:07:13 +03:00
onBack = { this . _handleBack }
onForward = { this . _handleForward }
2020-09-29 07:39:05 +03:00
onSignOut = { this . _handleSignOut }
2020-10-23 06:55:24 +03:00
mobile = { this . state . mobile }
2020-07-29 19:07:13 +03:00
/ >
) ;
2020-10-19 21:52:13 +03:00
const scene = React . cloneElement ( SCENES [ next . scene || current . target . decorator ] , {
current : current . target ,
data : this . state . data ,
viewer : this . state . viewer ,
selected : this . state . selected ,
onSelectedChange : this . _handleSelectedChange ,
onViewerChange : this . _handleViewerChange ,
onDeleteYourself : this . _handleDeleteYourself ,
onAction : this . _handleAction ,
onUpload : this . _handleUploadFiles ,
onBack : this . _handleBack ,
onForward : this . _handleForward ,
sceneId : current . target . id ,
2020-10-23 06:55:24 +03:00
mobile : this . state . mobile ,
2020-10-23 13:34:31 +03:00
resources : this . props . resources ,
2020-10-19 21:52:13 +03:00
} ) ;
2020-07-29 19:07:13 +03:00
let sidebarElement ;
if ( this . state . sidebar ) {
sidebarElement = React . cloneElement ( this . state . sidebar , {
2020-09-03 03:35:41 +03:00
current : current . target ,
2020-07-29 19:07:13 +03:00
selected : this . state . selected ,
viewer : this . state . viewer ,
data : this . state . data ,
2020-09-23 23:52:00 +03:00
sidebarData : this . state . sidebarData ,
2020-07-29 19:07:13 +03:00
fileLoading : this . state . fileLoading ,
sidebarLoading : this . state . sidebarLoading ,
onSelectedChange : this . _handleSelectedChange ,
onSubmit : this . _handleSubmit ,
2020-09-17 02:26:15 +03:00
onCancel : this . _handleDismissSidebar ,
2020-08-20 08:20:18 +03:00
onRegisterFileLoading : this . _handleRegisterFileLoading ,
2020-09-21 00:34:31 +03:00
onUpload : this . _handleUploadFiles ,
2020-07-29 19:07:13 +03:00
onSidebarLoading : this . _handleSidebarLoading ,
2020-08-09 11:08:46 +03:00
onAction : this . _handleAction ,
2020-10-23 13:34:31 +03:00
resources : this . props . resources ,
2020-07-29 19:07:13 +03:00
} ) ;
}
const title = ` Slate : ${ current . target . pageTitle } ` ;
2020-08-20 08:45:43 +03:00
const description = "" ;
2020-08-07 02:06:54 +03:00
const url = "https://slate.host/_" ;
2020-10-26 04:26:30 +03:00
2020-10-27 14:01:56 +03:00
console . log ( "application state:" , { target : current . target } ) ;
console . log ( "application state:" , { data : this . state . data } ) ;
2020-10-26 04:26:30 +03:00
2020-07-29 19:07:13 +03:00
return (
< React . Fragment >
2020-10-19 21:52:13 +03:00
< WebsitePrototypeWrapper description = { description } title = { title } url = { url } >
2020-07-29 19:07:13 +03:00
< ApplicationLayout
2020-09-25 06:16:10 +03:00
onAction = { this . _handleAction }
2020-07-29 19:07:13 +03:00
header = { headerElement }
2020-08-20 08:45:43 +03:00
navigation = { navigationElement }
2020-07-29 19:07:13 +03:00
sidebar = { sidebarElement }
2020-09-08 09:05:16 +03:00
onDismissSidebar = { this . _handleDismissSidebar }
2020-09-25 06:16:10 +03:00
fileLoading = { this . state . fileLoading }
2020-09-25 10:08:08 +03:00
filecoin = { current . target . filecoin }
2020-10-23 06:55:24 +03:00
mobile = { this . state . mobile }
2020-09-08 09:05:16 +03:00
>
2020-07-29 19:07:13 +03:00
{ scene }
< / A p p l i c a t i o n L a y o u t >
2020-10-14 02:29:14 +03:00
< System . GlobalCarousel
2020-10-24 09:36:52 +03:00
viewer = { this . state . viewer }
current = {
2020-10-24 22:55:19 +03:00
current . target &&
( current . target . decorator === "SLATE" || current . target . decorator === "HOME" )
2020-10-24 09:36:52 +03:00
? current . target
2020-10-24 22:55:19 +03:00
: this . state . data //NOTE(martina): for slates that are not your own
2020-10-24 09:36:52 +03:00
}
2020-10-14 02:29:14 +03:00
slates = { this . state . viewer . slates }
onAction = { this . _handleAction }
mobile = { this . props . mobile }
/ >
2020-08-25 02:24:29 +03:00
< System . GlobalModal / >
2020-07-29 19:07:13 +03:00
< / W e b s i t e P r o t o t y p e W r a p p e r >
< / R e a c t . F r a g m e n t >
) ;
}
}