mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-25 16:05:27 +03:00
Merge branch 'feat/spa' into lf/groups-refactor
This commit is contained in:
commit
ef20a4d08a
@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:58deed8e9b8cd2c84d092cb8f638b9881cb0d12b97f7c719339e3604c9e9d1d2
|
oid sha256:575484aaf6c8bc03ab3b962ca52d48a90113bcb38a29a1ac84f2d49d1363b4ba
|
||||||
size 13826033
|
size 7319532
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
:: invite-view: provide a json interface to invite-store
|
|
||||||
::
|
|
||||||
:: accepts subscriptions at the /primary path.
|
|
||||||
:: passes through all invites and their updates.
|
|
||||||
:: only accepts subcriptions from the host's team.
|
|
||||||
::
|
|
||||||
::TODO could maybe use /lib/proxy-hook, be renamed invite-proxy-hook
|
|
||||||
::
|
|
||||||
/+ *invite-json, default-agent, dbug
|
|
||||||
::
|
|
||||||
|%
|
|
||||||
+$ card card:agent:gall
|
|
||||||
--
|
|
||||||
::
|
|
||||||
=>
|
|
||||||
|%
|
|
||||||
++ watch-updates
|
|
||||||
|= our=ship
|
|
||||||
^- card
|
|
||||||
[%pass /store %agent [our %invite-store] %watch /updates]
|
|
||||||
--
|
|
||||||
::
|
|
||||||
%- agent:dbug
|
|
||||||
^- agent:gall
|
|
||||||
|_ =bowl:gall
|
|
||||||
+* this .
|
|
||||||
def ~(. (default-agent this %|) bowl)
|
|
||||||
::
|
|
||||||
++ on-init
|
|
||||||
^- (quip card _this)
|
|
||||||
[[(watch-updates our.bowl)]~ this]
|
|
||||||
::
|
|
||||||
++ on-save on-save:def
|
|
||||||
++ on-load
|
|
||||||
|= old=vase
|
|
||||||
^- (quip card _this)
|
|
||||||
[~ this]
|
|
||||||
::
|
|
||||||
++ on-watch
|
|
||||||
|= =path
|
|
||||||
^- (quip card _this)
|
|
||||||
?> (team:title our.bowl src.bowl)
|
|
||||||
?. =(/primary path)
|
|
||||||
(on-watch:def path)
|
|
||||||
:_ this
|
|
||||||
=/ =invites
|
|
||||||
.^(invites %gx /=invite-store/(scot %da now.bowl)/all/noun)
|
|
||||||
[%give %fact ~ %json !>((invites-to-json invites))]~
|
|
||||||
::
|
|
||||||
++ on-agent
|
|
||||||
|= [=wire =sign:agent:gall]
|
|
||||||
^- (quip card _this)
|
|
||||||
:_ this
|
|
||||||
?- -.sign
|
|
||||||
%poke-ack ~|([dap.bowl %unexpected-poke-ack] !!)
|
|
||||||
%watch-ack ~
|
|
||||||
%kick [(watch-updates our.bowl)]~
|
|
||||||
::
|
|
||||||
%fact
|
|
||||||
~| [dap.bowl %unexpected-fact-mark p.cage.sign]
|
|
||||||
?> ?=(%invite-update p.cage.sign)
|
|
||||||
:~ :*
|
|
||||||
%give %fact
|
|
||||||
~[/primary] %json
|
|
||||||
!>((update-to-json !<(invite-update q.cage.sign)))
|
|
||||||
== ==
|
|
||||||
==
|
|
||||||
::
|
|
||||||
++ on-poke on-poke:def
|
|
||||||
++ on-peek on-peek:def
|
|
||||||
++ on-leave on-leave:def
|
|
||||||
++ on-arvo on-arvo:def
|
|
||||||
++ on-fail on-fail:def
|
|
||||||
--
|
|
BIN
pkg/arvo/app/landscape/img/Link.png
Normal file
BIN
pkg/arvo/app/landscape/img/Link.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
@ -2161,7 +2161,6 @@
|
|||||||
[[[~ %json] [%'publish-view' %notebooks ~]] ~]
|
[[[~ %json] [%'publish-view' %notebooks ~]] ~]
|
||||||
%- json-response:gen
|
%- json-response:gen
|
||||||
%- json-to-octs
|
%- json-to-octs
|
||||||
%+ frond:enjs:format %publish-response
|
|
||||||
(notebooks-map:enjs our.bol books)
|
(notebooks-map:enjs our.bol books)
|
||||||
::
|
::
|
||||||
:: notes pagination
|
:: notes pagination
|
||||||
@ -2181,7 +2180,6 @@
|
|||||||
not-found:gen
|
not-found:gen
|
||||||
%- json-response:gen
|
%- json-response:gen
|
||||||
%- json-to-octs
|
%- json-to-octs
|
||||||
%+ frond:enjs:format %publish-response
|
|
||||||
:- %o
|
:- %o
|
||||||
(notes-page:enjs notes.u.book u.start u.length)
|
(notes-page:enjs notes.u.book u.start u.length)
|
||||||
::
|
::
|
||||||
@ -2206,7 +2204,6 @@
|
|||||||
not-found:gen
|
not-found:gen
|
||||||
%- json-response:gen
|
%- json-response:gen
|
||||||
%- json-to-octs
|
%- json-to-octs
|
||||||
%+ frond:enjs:format %publish-response
|
|
||||||
(comments-page:enjs comments.u.note u.start u.length)
|
(comments-page:enjs comments.u.note u.start u.length)
|
||||||
::
|
::
|
||||||
:: single notebook with initial 50 notes in short form, as json
|
:: single notebook with initial 50 notes in short form, as json
|
||||||
@ -2225,9 +2222,7 @@
|
|||||||
(~(put by p.notebook-json) %subscribers (get-subscribers-json book-name))
|
(~(put by p.notebook-json) %subscribers (get-subscribers-json book-name))
|
||||||
=. p.notebook-json
|
=. p.notebook-json
|
||||||
(~(put by p.notebook-json) %writers (get-writers-json u.host book-name))
|
(~(put by p.notebook-json) %writers (get-writers-json u.host book-name))
|
||||||
=/ jon=json
|
(json-response:gen (json-to-octs (pairs notebook+notebook-json ~)))
|
||||||
(frond:enjs:format %publish-response (pairs notebook+notebook-json ~))
|
|
||||||
(json-response:gen (json-to-octs jon))
|
|
||||||
::
|
::
|
||||||
:: single note, with initial 50 comments, as json
|
:: single note, with initial 50 comments, as json
|
||||||
[[[~ %json] [%'publish-view' @ @ @ ~]] ~]
|
[[[~ %json] [%'publish-view' @ @ @ ~]] ~]
|
||||||
@ -2241,7 +2236,6 @@
|
|||||||
=/ note=(unit note) (~(get by notes.u.book) note-name)
|
=/ note=(unit note) (~(get by notes.u.book) note-name)
|
||||||
?~ note not-found:gen
|
?~ note not-found:gen
|
||||||
=/ jon=json
|
=/ jon=json
|
||||||
%+ frond %publish-response
|
|
||||||
o+(note-presentation:enjs u.book note-name u.note)
|
o+(note-presentation:enjs u.book note-name u.note)
|
||||||
(json-response:gen (json-to-octs jon))
|
(json-response:gen (json-to-octs jon))
|
||||||
==
|
==
|
||||||
|
@ -56,26 +56,23 @@
|
|||||||
[%read (numb read.config)]
|
[%read (numb read.config)]
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ inbox
|
|
||||||
|= box=^inbox
|
|
||||||
^- json
|
|
||||||
%+ frond %chat-initial
|
|
||||||
%- pairs
|
|
||||||
%+ turn ~(tap by box)
|
|
||||||
|= [pax=^path =mailbox]
|
|
||||||
^- [cord json]
|
|
||||||
:- (spat pax)
|
|
||||||
%- pairs
|
|
||||||
:~ [%envelopes [%a (turn envelopes.mailbox envelope)]]
|
|
||||||
[%config (config config.mailbox)]
|
|
||||||
==
|
|
||||||
::
|
|
||||||
++ update
|
++ update
|
||||||
|= upd=^update
|
|= upd=^update
|
||||||
^- json
|
^- json
|
||||||
%+ frond %chat-update
|
%+ frond %chat-update
|
||||||
%- pairs
|
%- pairs
|
||||||
:~
|
:~
|
||||||
|
?: ?=(%initial -.upd)
|
||||||
|
:- %initial
|
||||||
|
%- pairs
|
||||||
|
%+ turn ~(tap by inbox.upd)
|
||||||
|
|= [pax=^path =mailbox]
|
||||||
|
^- [cord json]
|
||||||
|
:- (spat pax)
|
||||||
|
%- pairs
|
||||||
|
:~ [%envelopes [%a (turn envelopes.mailbox envelope)]]
|
||||||
|
[%config (config config.mailbox)]
|
||||||
|
==
|
||||||
?: ?=(%message -.upd)
|
?: ?=(%message -.upd)
|
||||||
:- %message
|
:- %message
|
||||||
%- pairs
|
%- pairs
|
||||||
|
@ -104,7 +104,6 @@
|
|||||||
%permission-group-hook
|
%permission-group-hook
|
||||||
%invite-store
|
%invite-store
|
||||||
%invite-hook
|
%invite-hook
|
||||||
%invite-view
|
|
||||||
%chat-store
|
%chat-store
|
||||||
%chat-hook
|
%chat-hook
|
||||||
%chat-view
|
%chat-view
|
||||||
|
@ -979,7 +979,7 @@
|
|||||||
=/ actual-redirect ?:(=(u.redirect '') '/' u.redirect)
|
=/ actual-redirect ?:(=(u.redirect '') '/' u.redirect)
|
||||||
%- handle-response
|
%- handle-response
|
||||||
:* %start
|
:* %start
|
||||||
:- status-code=307
|
:- status-code=303
|
||||||
^= headers
|
^= headers
|
||||||
:~ ['location' actual-redirect]
|
:~ ['location' actual-redirect]
|
||||||
['set-cookie' cookie-line]
|
['set-cookie' cookie-line]
|
||||||
|
@ -613,12 +613,12 @@
|
|||||||
^- (hypo sign:http-server-gate) :- *type
|
^- (hypo sign:http-server-gate) :- *type
|
||||||
:* %g %unto %fact
|
:* %g %unto %fact
|
||||||
%http-response-header
|
%http-response-header
|
||||||
!>([307 ['location' '/~/login?redirect=/~landscape/inner-path']~])
|
!>([303 ['location' '/~/login?redirect=/~landscape/inner-path']~])
|
||||||
==
|
==
|
||||||
==
|
==
|
||||||
^= expected-move
|
^= expected-move
|
||||||
:~ :* duct=~[/http-blah] %give %response
|
:~ :* duct=~[/http-blah] %give %response
|
||||||
[%start [307 ['location' '/~/login?redirect=/~landscape/inner-path']~] ~ %.n]
|
[%start [303 ['location' '/~/login?redirect=/~landscape/inner-path']~] ~ %.n]
|
||||||
== == ==
|
== == ==
|
||||||
:: the browser then fetches the login page
|
:: the browser then fetches the login page
|
||||||
::
|
::
|
||||||
@ -2152,7 +2152,7 @@
|
|||||||
%give
|
%give
|
||||||
%response
|
%response
|
||||||
%start
|
%start
|
||||||
:- 307
|
:- 303
|
||||||
:~ ['location' '/~landscape']
|
:~ ['location' '/~landscape']
|
||||||
:- 'set-cookie'
|
:- 'set-cookie'
|
||||||
'urbauth-~nul=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea; Path=/; Max-Age=604800'
|
'urbauth-~nul=0v3.q0p7t.mlkkq.cqtto.p0nvi.2ieea; Path=/; Max-Age=604800'
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
URBIT_PIERS: [
|
URBIT_PIERS: [
|
||||||
"/Users/user/ships/zod/home",
|
"/Users/user/ships/zod/home",
|
||||||
]
|
],
|
||||||
|
herb: false
|
||||||
};
|
};
|
||||||
|
@ -2,6 +2,41 @@ const path = require('path');
|
|||||||
// const HtmlWebpackPlugin = require('html-webpack-plugin');
|
// const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
// const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
// const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||||
const urbitrc = require('./urbitrc');
|
const urbitrc = require('./urbitrc');
|
||||||
|
const fs = require('fs');
|
||||||
|
const util = require('util');
|
||||||
|
const exec = util.promisify(require('child_process').exec);
|
||||||
|
|
||||||
|
function copyFile(src,dest) {
|
||||||
|
return new Promise((res,rej) =>
|
||||||
|
fs.copyFile(src,dest, err => err ? rej(err) : res()));
|
||||||
|
}
|
||||||
|
|
||||||
|
class UrbitShipPlugin {
|
||||||
|
constructor(urbitrc) {
|
||||||
|
this.piers = urbitrc.URBIT_PIERS;
|
||||||
|
this.herb = urbitrc.herb || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(compiler) {
|
||||||
|
compiler.hooks.afterCompile.tapPromise(
|
||||||
|
'UrbitShipPlugin',
|
||||||
|
async (compilation) => {
|
||||||
|
const src = path.resolve(compiler.options.output.path, 'index.js');
|
||||||
|
return Promise.all(this.piers.map(pier => {
|
||||||
|
const dst = path.resolve(pier, 'app/landscape/js/index.js');
|
||||||
|
copyFile(src, dst).then(() => {
|
||||||
|
if(!this.herb) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pier = pier.split('/');
|
||||||
|
const desk = pier.pop();
|
||||||
|
return exec(`herb -p hood -d '+hood/commit %${desk}' ${pier.join('/')}`);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mode: 'development',
|
mode: 'development',
|
||||||
@ -49,16 +84,18 @@ module.exports = {
|
|||||||
// historyApiFallback: true
|
// historyApiFallback: true
|
||||||
// },
|
// },
|
||||||
plugins: [
|
plugins: [
|
||||||
|
new UrbitShipPlugin(urbitrc)
|
||||||
// new CleanWebpackPlugin(),
|
// new CleanWebpackPlugin(),
|
||||||
// new HtmlWebpackPlugin({
|
// new HtmlWebpackPlugin({
|
||||||
// title: 'Hot Module Replacement',
|
// title: 'Hot Module Replacement',
|
||||||
// template: './public/index.html',
|
// template: './public/index.html',
|
||||||
// }),
|
// }),
|
||||||
],
|
],
|
||||||
|
watch: true,
|
||||||
output: {
|
output: {
|
||||||
filename: 'index.js',
|
filename: 'index.js',
|
||||||
chunkFilename: 'index.js',
|
chunkFilename: 'index.js',
|
||||||
path: path.resolve(urbitrc.URBIT_PIERS[0] + '/app/landscape/', 'js'),
|
path: path.resolve(__dirname, '../dist'),
|
||||||
publicPath: '/'
|
publicPath: '/'
|
||||||
},
|
},
|
||||||
optimization: {
|
optimization: {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { BrowserRouter as Router, Route, Link, withRouter } from 'react-router-dom';
|
import { BrowserRouter as Router, Route, withRouter, Switch } from 'react-router-dom';
|
||||||
import styled, { ThemeProvider, createGlobalStyle } from 'styled-components';
|
import styled, { ThemeProvider, createGlobalStyle } from 'styled-components';
|
||||||
import './css/indigo-static.css';
|
import './css/indigo-static.css';
|
||||||
import './css/fonts.css';
|
import './css/fonts.css';
|
||||||
@ -8,11 +8,13 @@ import { light } from '@tlon/indigo-react';
|
|||||||
import LaunchApp from './apps/launch/app';
|
import LaunchApp from './apps/launch/app';
|
||||||
import ChatApp from './apps/chat/app';
|
import ChatApp from './apps/chat/app';
|
||||||
import DojoApp from './apps/dojo/app';
|
import DojoApp from './apps/dojo/app';
|
||||||
import StatusBar from './components/StatusBar';
|
|
||||||
import GroupsApp from './apps/groups/app';
|
import GroupsApp from './apps/groups/app';
|
||||||
import LinksApp from './apps/links/app';
|
import LinksApp from './apps/links/app';
|
||||||
import PublishApp from './apps/publish/app';
|
import PublishApp from './apps/publish/app';
|
||||||
|
|
||||||
|
import StatusBar from './components/StatusBar';
|
||||||
|
import NotFound from './components/404';
|
||||||
|
|
||||||
import GlobalStore from './store/global';
|
import GlobalStore from './store/global';
|
||||||
import GlobalSubscription from './subscription/global';
|
import GlobalSubscription from './subscription/global';
|
||||||
import GlobalApi from './api/global';
|
import GlobalApi from './api/global';
|
||||||
@ -71,48 +73,64 @@ export default class App extends React.Component {
|
|||||||
api={this.api}
|
api={this.api}
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<Route exact path="/" render={ p => (
|
<Switch>
|
||||||
|
<Route exact path="/"
|
||||||
|
render={ p => (
|
||||||
<LaunchApp
|
<LaunchApp
|
||||||
ship={this.ship}
|
ship={this.ship}
|
||||||
channel={channel}
|
channel={channel}
|
||||||
selectedGroups={selectedGroups}
|
selectedGroups={selectedGroups}
|
||||||
{...p} />
|
{...p}
|
||||||
)} />
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
<Route path="/~chat" render={ p => (
|
<Route path="/~chat" render={ p => (
|
||||||
<ChatApp
|
<ChatApp
|
||||||
ship={this.ship}
|
ship={this.ship}
|
||||||
channel={channel}
|
channel={channel}
|
||||||
selectedGroups={selectedGroups}
|
selectedGroups={selectedGroups}
|
||||||
{...p} />
|
{...p}
|
||||||
)} />
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
<Route path="/~dojo" render={ p => (
|
<Route path="/~dojo" render={ p => (
|
||||||
<DojoApp
|
<DojoApp
|
||||||
ship={this.ship}
|
ship={this.ship}
|
||||||
channel={channel}
|
channel={channel}
|
||||||
selectedGroups={selectedGroups}
|
selectedGroups={selectedGroups}
|
||||||
{...p} />
|
{...p}
|
||||||
)} />
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
<Route path="/~groups" render={ p => (
|
<Route path="/~groups" render={ p => (
|
||||||
<GroupsApp
|
<GroupsApp
|
||||||
ship={this.ship}
|
ship={this.ship}
|
||||||
channel={channel}
|
channel={channel}
|
||||||
selectedGroups={selectedGroups}
|
selectedGroups={selectedGroups}
|
||||||
{...p} />
|
{...p}
|
||||||
)} />
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
<Route path="/~link" render={ p => (
|
<Route path="/~link" render={ p => (
|
||||||
<LinksApp
|
<LinksApp
|
||||||
ship={this.ship}
|
ship={this.ship}
|
||||||
channel={channel}
|
channel={channel}
|
||||||
selectedGroups={selectedGroups}
|
selectedGroups={selectedGroups}
|
||||||
{...p} />
|
{...p}
|
||||||
)} />
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
<Route path="/~publish" render={ p => (
|
<Route path="/~publish" render={ p => (
|
||||||
<PublishApp
|
<PublishApp
|
||||||
ship={this.ship}
|
ship={this.ship}
|
||||||
channel={channel}
|
channel={channel}
|
||||||
selectedGroups={selectedGroups}
|
selectedGroups={selectedGroups}
|
||||||
{...p} />
|
{...p}
|
||||||
)} />
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Route component={NotFound} />
|
||||||
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
</Router>
|
</Router>
|
||||||
</Root>
|
</Root>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import BaseApi from './base';
|
import BaseApi from './base';
|
||||||
|
import { uuid } from '../lib/util';
|
||||||
|
|
||||||
export default class ChatApi {
|
export default class ChatApi {
|
||||||
constructor(ship, channel, store) {
|
constructor(ship, channel, store) {
|
||||||
@ -36,6 +37,7 @@ export default class ChatApi {
|
|||||||
this.metadata = {
|
this.metadata = {
|
||||||
add: helper.metadataAdd.bind(helper)
|
add: helper.metadataAdd.bind(helper)
|
||||||
};
|
};
|
||||||
|
this.sidebarToggle = helper.sidebarToggle.bind(helper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +68,7 @@ class PrivateHelper extends BaseApi {
|
|||||||
|
|
||||||
addPendingMessage(msg) {
|
addPendingMessage(msg) {
|
||||||
if (this.store.state.pendingMessages.has(msg.path)) {
|
if (this.store.state.pendingMessages.has(msg.path)) {
|
||||||
this.store.state.pendingMessages.get(msg.path).push(msg.envelope);
|
this.store.state.pendingMessages.get(msg.path).unshift(msg.envelope);
|
||||||
} else {
|
} else {
|
||||||
this.store.state.pendingMessages.set(msg.path, [msg.envelope]);
|
this.store.state.pendingMessages.set(msg.path, [msg.envelope]);
|
||||||
}
|
}
|
||||||
@ -203,5 +205,18 @@ class PrivateHelper extends BaseApi {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sidebarToggle() {
|
||||||
|
let sidebarBoolean = true;
|
||||||
|
if (this.store.state.sidebarShown === true) {
|
||||||
|
sidebarBoolean = false;
|
||||||
|
}
|
||||||
|
this.store.handleEvent({
|
||||||
|
data: {
|
||||||
|
local: {
|
||||||
|
sidebarToggle: sidebarBoolean
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,11 @@ export default class GroupsApi {
|
|||||||
|
|
||||||
this.group = {
|
this.group = {
|
||||||
add: helper.groupAdd.bind(helper),
|
add: helper.groupAdd.bind(helper),
|
||||||
delete: helper.groupRemove.bind(helper)
|
remove: helper.groupRemove.bind(helper)
|
||||||
|
};
|
||||||
|
|
||||||
|
this.metadata = {
|
||||||
|
add: helper.metadataAdd.bind(helper)
|
||||||
};
|
};
|
||||||
|
|
||||||
this.invite = {
|
this.invite = {
|
||||||
|
@ -24,6 +24,14 @@ class PrivateHelper extends BaseApi {
|
|||||||
launchChangeIsShown(name, isShown = true) {
|
launchChangeIsShown(name, isShown = true) {
|
||||||
this.launchAction({ 'change-is-shown': { name, isShown }});
|
this.launchAction({ 'change-is-shown': { name, isShown }});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clockAction(latlng) {
|
||||||
|
return this.action('clock', 'json', latlng);
|
||||||
|
}
|
||||||
|
|
||||||
|
weatherAction(latlng) {
|
||||||
|
return this.action('weather', 'json', latlng);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class LaunchApi {
|
export default class LaunchApi {
|
||||||
@ -40,6 +48,10 @@ export default class LaunchApi {
|
|||||||
changeFirstTime: helper.launchChangeFirstTime.bind(helper),
|
changeFirstTime: helper.launchChangeFirstTime.bind(helper),
|
||||||
changeIsShown: helper.launchChangeIsShown.bind(helper)
|
changeIsShown: helper.launchChangeIsShown.bind(helper)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.clock = { action: helper.clockAction.bind(helper) };
|
||||||
|
|
||||||
|
this.weather ={ action: helper.weatherAction.bind(helper) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import _ from 'lodash';
|
|
||||||
import { stringToTa } from '../lib/util';
|
import { stringToTa } from '../lib/util';
|
||||||
|
|
||||||
import BaseApi from './base';
|
import BaseApi from './base';
|
||||||
|
|
||||||
|
|
||||||
export default class LinksApi extends BaseApi {
|
export default class LinksApi extends BaseApi {
|
||||||
constructor(ship, channel, store) {
|
constructor(ship, channel, store) {
|
||||||
super(ship, channel, store);
|
super(ship, channel, store);
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import BaseApi from './base';
|
import BaseApi from './base';
|
||||||
|
|
||||||
|
|
||||||
export default class PublishApi extends BaseApi {
|
export default class PublishApi extends BaseApi {
|
||||||
|
handleEvent(data) {
|
||||||
|
this.store.handleEvent({ data: { 'publish-response' : data } });
|
||||||
|
}
|
||||||
|
|
||||||
fetchNotebooks() {
|
fetchNotebooks() {
|
||||||
fetch('/publish-view/notebooks.json')
|
fetch('/publish-view/notebooks.json')
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
this.store.handleEvent({
|
this.handleEvent({
|
||||||
type: 'notebooks',
|
type: 'notebooks',
|
||||||
data: json
|
data: json
|
||||||
});
|
});
|
||||||
@ -17,7 +20,7 @@ export default class PublishApi extends BaseApi {
|
|||||||
fetch(`/publish-view/${host}/${book}.json`)
|
fetch(`/publish-view/${host}/${book}.json`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
this.store.handleEvent({
|
this.handleEvent({
|
||||||
type: 'notebook',
|
type: 'notebook',
|
||||||
data: json,
|
data: json,
|
||||||
host: host,
|
host: host,
|
||||||
@ -30,7 +33,7 @@ export default class PublishApi extends BaseApi {
|
|||||||
fetch(`/publish-view/${host}/${book}/${note}.json`)
|
fetch(`/publish-view/${host}/${book}/${note}.json`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
this.store.handleEvent({
|
this.handleEvent({
|
||||||
type: 'note',
|
type: 'note',
|
||||||
data: json,
|
data: json,
|
||||||
host: host,
|
host: host,
|
||||||
@ -44,7 +47,7 @@ export default class PublishApi extends BaseApi {
|
|||||||
fetch(`/publish-view/notes/${host}/${book}/${start}/${length}.json`)
|
fetch(`/publish-view/notes/${host}/${book}/${start}/${length}.json`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
this.store.handleEvent({
|
this.handleEvent({
|
||||||
type: 'notes-page',
|
type: 'notes-page',
|
||||||
data: json,
|
data: json,
|
||||||
host: host,
|
host: host,
|
||||||
@ -59,7 +62,7 @@ export default class PublishApi extends BaseApi {
|
|||||||
fetch(`/publish-view/comments/${host}/${book}/${note}/${start}/${length}.json`)
|
fetch(`/publish-view/comments/${host}/${book}/${note}/${start}/${length}.json`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
this.store.handleEvent({
|
this.handleEvent({
|
||||||
type: 'comments-page',
|
type: 'comments-page',
|
||||||
data: json,
|
data: json,
|
||||||
host: host,
|
host: host,
|
||||||
@ -71,15 +74,28 @@ export default class PublishApi extends BaseApi {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
groupAction(act) {
|
||||||
|
return this.action('group-store', 'group-action', act);
|
||||||
|
}
|
||||||
|
|
||||||
|
inviteAction(act) {
|
||||||
|
return this.action('invite-store', 'invite-action', act);
|
||||||
|
}
|
||||||
|
|
||||||
|
publishAction(act) {
|
||||||
|
return this.action('publish', 'publish-action', act);
|
||||||
|
}
|
||||||
|
|
||||||
sidebarToggle() {
|
sidebarToggle() {
|
||||||
let sidebarBoolean = true;
|
let sidebarBoolean = true;
|
||||||
if (this.store.state.sidebarShown === true) {
|
if (this.store.state.sidebarShown === true) {
|
||||||
sidebarBoolean = false;
|
sidebarBoolean = false;
|
||||||
}
|
}
|
||||||
this.store.handleEvent({
|
this.store.handleEvent({
|
||||||
type: 'local',
|
|
||||||
data: {
|
data: {
|
||||||
'sidebarToggle': sidebarBoolean
|
local: {
|
||||||
|
sidebarToggle: sidebarBoolean
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ export default class ChatApp extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
window.title = 'OS1 - Chat';
|
document.title = 'OS1 - Chat';
|
||||||
// preload spinner asset
|
// preload spinner asset
|
||||||
new Image().src = '/~landscape/img/Spinner.png';
|
new Image().src = '/~landscape/img/Spinner.png';
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ export default class ChatApp extends React.Component {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (totalUnreads !== this.totalUnreads) {
|
if (totalUnreads !== this.totalUnreads) {
|
||||||
document.title = totalUnreads > 0 ? `Chat - (${totalUnreads})` : 'Chat';
|
document.title = totalUnreads > 0 ? `OS1 - Chat (${totalUnreads})` : 'OS1 - Chat';
|
||||||
this.totalUnreads = totalUnreads;
|
this.totalUnreads = totalUnreads;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +310,7 @@ export default class ChatApp extends React.Component {
|
|||||||
>
|
>
|
||||||
<MemberScreen
|
<MemberScreen
|
||||||
{...props}
|
{...props}
|
||||||
api={api}
|
api={this.api}
|
||||||
station={station}
|
station={station}
|
||||||
association={association}
|
association={association}
|
||||||
permission={permission}
|
permission={permission}
|
||||||
@ -361,7 +361,7 @@ export default class ChatApp extends React.Component {
|
|||||||
permissions={state.permissions || {}}
|
permissions={state.permissions || {}}
|
||||||
contacts={state.contacts || {}}
|
contacts={state.contacts || {}}
|
||||||
associations={associations.contacts}
|
associations={associations.contacts}
|
||||||
api={api}
|
api={this.api}
|
||||||
inbox={state.inbox}
|
inbox={state.inbox}
|
||||||
popout={popout}
|
popout={popout}
|
||||||
sidebarShown={state.sidebarShown}
|
sidebarShown={state.sidebarShown}
|
||||||
|
@ -493,9 +493,9 @@ ref={(e) => {
|
|||||||
style={{ height: 48 }}
|
style={{ height: 48 }}
|
||||||
>
|
>
|
||||||
<SidebarSwitcher
|
<SidebarSwitcher
|
||||||
sidebarShown={this.props.sidebarShown}
|
sidebarShown={props.sidebarShown}
|
||||||
popout={this.props.popout}
|
popout={props.popout}
|
||||||
api={this.props.api}
|
api={props.api}
|
||||||
/>
|
/>
|
||||||
<Link to={'/~chat/' + isinPopout + 'room' + props.station}
|
<Link to={'/~chat/' + isinPopout + 'room' + props.station}
|
||||||
className="pt2 white-d"
|
className="pt2 white-d"
|
||||||
@ -513,7 +513,7 @@ ref={(e) => {
|
|||||||
station={props.station}
|
station={props.station}
|
||||||
numPeers={group.length}
|
numPeers={group.length}
|
||||||
isOwner={deSig(props.match.params.ship) === window.ship}
|
isOwner={deSig(props.match.params.ship) === window.ship}
|
||||||
popout={this.props.popout}
|
popout={props.popout}
|
||||||
api={props.api}
|
api={props.api}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -108,7 +108,7 @@ export class SettingsScreen extends Component {
|
|||||||
|
|
||||||
if (chatOwner) {
|
if (chatOwner) {
|
||||||
this.setState({ awaiting: true, type: 'Editing chat...' }, (() => {
|
this.setState({ awaiting: true, type: 'Editing chat...' }, (() => {
|
||||||
props.api.metadataAdd(
|
props.api.metadata.add(
|
||||||
association['app-path'],
|
association['app-path'],
|
||||||
association['group-path'],
|
association['group-path'],
|
||||||
association.metadata.title,
|
association.metadata.title,
|
||||||
@ -272,16 +272,16 @@ export class SettingsScreen extends Component {
|
|||||||
<input
|
<input
|
||||||
className={'f8 ba b--gray3 b--gray2-d bg-gray0-d white-d ' +
|
className={'f8 ba b--gray3 b--gray2-d bg-gray0-d white-d ' +
|
||||||
'focus-b--black focus-b--white-d pa3 db w-100 flex-auto mr3'}
|
'focus-b--black focus-b--white-d pa3 db w-100 flex-auto mr3'}
|
||||||
value={this.state.title}
|
value={state.title}
|
||||||
disabled={!chatOwner}
|
disabled={!chatOwner}
|
||||||
onChange={this.changeTitle}
|
onChange={this.changeTitle}
|
||||||
onBlur={() => {
|
onBlur={() => {
|
||||||
if (chatOwner) {
|
if (chatOwner) {
|
||||||
this.setState({ awaiting: true, type: 'Editing chat...' }, (() => {
|
this.setState({ awaiting: true, type: 'Editing chat...' }, (() => {
|
||||||
props.api.metadataAdd(
|
props.api.metadata.add(
|
||||||
association['app-path'],
|
association['app-path'],
|
||||||
association['group-path'],
|
association['group-path'],
|
||||||
this.state.title,
|
state.title,
|
||||||
association.metadata.description,
|
association.metadata.description,
|
||||||
association.metadata['date-created'],
|
association.metadata['date-created'],
|
||||||
uxToHex(association.metadata.color)
|
uxToHex(association.metadata.color)
|
||||||
@ -301,17 +301,17 @@ export class SettingsScreen extends Component {
|
|||||||
<input
|
<input
|
||||||
className={'f8 ba b--gray3 b--gray2-d bg-gray0-d white-d ' +
|
className={'f8 ba b--gray3 b--gray2-d bg-gray0-d white-d ' +
|
||||||
'focus-b--black focus-b--white-d pa3 db w-100 flex-auto mr3'}
|
'focus-b--black focus-b--white-d pa3 db w-100 flex-auto mr3'}
|
||||||
value={this.state.description}
|
value={state.description}
|
||||||
disabled={!chatOwner}
|
disabled={!chatOwner}
|
||||||
onChange={this.changeDescription}
|
onChange={this.changeDescription}
|
||||||
onBlur={() => {
|
onBlur={() => {
|
||||||
if (chatOwner) {
|
if (chatOwner) {
|
||||||
this.setState({ awaiting: true, type: 'Editing chat...' }, (() => {
|
this.setState({ awaiting: true, type: 'Editing chat...' }, (() => {
|
||||||
props.api.metadataAdd(
|
props.api.metadata.add(
|
||||||
association['app-path'],
|
association['app-path'],
|
||||||
association['group-path'],
|
association['group-path'],
|
||||||
association.metadata.title,
|
association.metadata.title,
|
||||||
this.state.description,
|
state.description,
|
||||||
association.metadata['date-created'],
|
association.metadata['date-created'],
|
||||||
uxToHex(association.metadata.color)
|
uxToHex(association.metadata.color)
|
||||||
).then(() => {
|
).then(() => {
|
||||||
@ -339,7 +339,7 @@ export class SettingsScreen extends Component {
|
|||||||
<input
|
<input
|
||||||
className={'pl7 f8 ba b--gray3 b--gray2-d bg-gray0-d white-d ' +
|
className={'pl7 f8 ba b--gray3 b--gray2-d bg-gray0-d white-d ' +
|
||||||
'focus-b--black focus-b--white-d pa3 db w-100 flex-auto mr3'}
|
'focus-b--black focus-b--white-d pa3 db w-100 flex-auto mr3'}
|
||||||
value={this.state.color}
|
value={state.color}
|
||||||
disabled={!chatOwner}
|
disabled={!chatOwner}
|
||||||
onChange={this.changeColor}
|
onChange={this.changeColor}
|
||||||
onBlur={this.submitColor}
|
onBlur={this.submitColor}
|
||||||
@ -400,7 +400,9 @@ export class SettingsScreen extends Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-100 pl3 mt4 cf">
|
<div className="w-100 pl3 mt4 cf">
|
||||||
<Spinner awaiting={this.state.awaiting} classes="absolute right-2 bottom-2 ba pa2 b--gray1-d" text={this.state.type} />
|
<Spinner awaiting={state.awaiting}
|
||||||
|
classes="absolute right-2 bottom-2 ba pa2 b--gray1-d"
|
||||||
|
text={state.type} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -477,7 +479,9 @@ export class SettingsScreen extends Component {
|
|||||||
{this.renderGroupify()}
|
{this.renderGroupify()}
|
||||||
{this.renderDelete()}
|
{this.renderDelete()}
|
||||||
{this.renderMetadataSettings()}
|
{this.renderMetadataSettings()}
|
||||||
<Spinner awaiting={this.state.awaiting} classes="absolute right-2 bottom-2 ba pa2 b--gray1-d" text={this.state.type} />
|
<Spinner awaiting={state.awaiting}
|
||||||
|
classes="absolute right-2 bottom-2 ba pa2 b--gray1-d"
|
||||||
|
text={state.type} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -14,6 +14,7 @@ export class Sidebar extends Component {
|
|||||||
dmOverlay: false
|
dmOverlay: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickNew() {
|
onClickNew() {
|
||||||
this.props.history.push('/~chat/new');
|
this.props.history.push('/~chat/new');
|
||||||
}
|
}
|
||||||
@ -37,10 +38,14 @@ export class Sidebar extends Component {
|
|||||||
|
|
||||||
const selectedGroups = props.selectedGroups ? props.selectedGroups : [];
|
const selectedGroups = props.selectedGroups ? props.selectedGroups : [];
|
||||||
|
|
||||||
const associations =
|
const contactAssoc =
|
||||||
(props.associations && 'contacts' in props.associations)
|
(props.associations && 'contacts' in props.associations)
|
||||||
? alphabetiseAssociations(props.associations.contacts) : {};
|
? alphabetiseAssociations(props.associations.contacts) : {};
|
||||||
|
|
||||||
|
const chatAssoc =
|
||||||
|
(props.associations && 'chat' in props.associations)
|
||||||
|
? alphabetiseAssociations(props.associations.chat) : {};
|
||||||
|
|
||||||
const groupedChannels = {};
|
const groupedChannels = {};
|
||||||
Object.keys(props.inbox).map((box) => {
|
Object.keys(props.inbox).map((box) => {
|
||||||
if (box.startsWith('/~/')) {
|
if (box.startsWith('/~/')) {
|
||||||
@ -51,16 +56,18 @@ export class Sidebar extends Component {
|
|||||||
} else {
|
} else {
|
||||||
groupedChannels['/~/'] = [box];
|
groupedChannels['/~/'] = [box];
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
const path = props.associations.chat[box]
|
const path = chatAssoc[box]
|
||||||
? props.associations.chat[box]['group-path'] : box;
|
? chatAssoc[box]['group-path'] : box;
|
||||||
if (path in associations) {
|
|
||||||
if (groupedChannels[path]) {
|
if (path in contactAssoc) {
|
||||||
const array = groupedChannels[path];
|
if (groupedChannels[path]) {
|
||||||
array.push(box);
|
const array = groupedChannels[path];
|
||||||
groupedChannels[path] = array;
|
array.push(box);
|
||||||
} else {
|
groupedChannels[path] = array;
|
||||||
groupedChannels[path] = [box];
|
} else {
|
||||||
|
groupedChannels[path] = [box];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -77,7 +84,7 @@ export class Sidebar extends Component {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const groupedItems = Object.keys(associations)
|
const groupedItems = Object.keys(contactAssoc)
|
||||||
.filter(each => (groupedChannels[each] || []).length !== 0)
|
.filter(each => (groupedChannels[each] || []).length !== 0)
|
||||||
.filter((each) => {
|
.filter((each) => {
|
||||||
if (selectedGroups.length === 0) {
|
if (selectedGroups.length === 0) {
|
||||||
@ -94,8 +101,8 @@ export class Sidebar extends Component {
|
|||||||
<GroupItem
|
<GroupItem
|
||||||
key={i}
|
key={i}
|
||||||
index={i}
|
index={i}
|
||||||
association={associations[each]}
|
association={contactAssoc[each]}
|
||||||
chatMetadata={props.associations['chat']}
|
chatMetadata={chatAssoc}
|
||||||
channels={channels}
|
channels={channels}
|
||||||
inbox={props.inbox}
|
inbox={props.inbox}
|
||||||
station={props.station}
|
station={props.station}
|
||||||
@ -108,7 +115,7 @@ export class Sidebar extends Component {
|
|||||||
groupedItems.push(
|
groupedItems.push(
|
||||||
<GroupItem
|
<GroupItem
|
||||||
association={'/~/'}
|
association={'/~/'}
|
||||||
chatMetadata={props.associations['chat']}
|
chatMetadata={chatAssoc}
|
||||||
channels={groupedChannels['/~/']}
|
channels={groupedChannels['/~/']}
|
||||||
inbox={props.inbox}
|
inbox={props.inbox}
|
||||||
station={props.station}
|
station={props.station}
|
||||||
|
@ -51,7 +51,7 @@ h2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.clamp-attachment {
|
.clamp-attachment {
|
||||||
overflow: scroll;
|
overflow: auto;
|
||||||
max-height: 10em;
|
max-height: 10em;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ export default class DojoApp extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
window.title = 'OS1 - Dojo';
|
document.title = 'OS1 - Dojo';
|
||||||
|
|
||||||
const channel = new this.props.channel();
|
const channel = new this.props.channel();
|
||||||
this.api = new Api(this.props.ship, channel);
|
this.api = new Api(this.props.ship, channel);
|
||||||
@ -47,7 +47,7 @@ export default class DojoApp extends Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="bg-white bg-gray1-d"
|
className="bg-white bg-gray0-d"
|
||||||
style={{ height: 'calc(100vh - 45px)' }}
|
style={{ height: 'calc(100vh - 45px)' }}
|
||||||
>
|
>
|
||||||
<Route
|
<Route
|
||||||
@ -72,7 +72,7 @@ export default class DojoApp extends Component {
|
|||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'pa3 bg-white bg-gray0-d black white-d mono w-100 f8 relative' +
|
'pa3 bg-white bg-gray0-d black white-d mono w-100 f8 relative' +
|
||||||
' h-100-m40-s b--gray2 br1 flex-auto ' +
|
' h-100-m40-s b--gray2 br1 flex-auto flex flex-column ' +
|
||||||
popoutClasses
|
popoutClasses
|
||||||
}
|
}
|
||||||
style={{
|
style={{
|
||||||
|
@ -8,8 +8,8 @@ export class History extends Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="relative flex flex-column-reverse overflow-container flex-auto"
|
className="h-100 relative flex flex-column-reverse overflow-container flex-auto"
|
||||||
style={{ height: 'calc(100% - 1rem)', resize: 'none' }}
|
style={{ resize: 'none' }}
|
||||||
>
|
>
|
||||||
<div style={{ marginTop: 'auto' }}>
|
<div style={{ marginTop: 'auto' }}>
|
||||||
{this.props.commandLog.map((text, index) => {
|
{this.props.commandLog.map((text, index) => {
|
||||||
|
@ -7,7 +7,7 @@ export class Popout extends Component {
|
|||||||
: 'dib-m dib-l dib-xl';
|
: 'dib-m dib-l dib-xl';
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="dib absolute z-2"
|
className="db tr z-2"
|
||||||
style={{
|
style={{
|
||||||
right: 16,
|
right: 16,
|
||||||
top: 16
|
top: 16
|
||||||
|
@ -23,7 +23,7 @@ export default class GroupsApp extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
window.title = 'OS1 - Groups';
|
document.title = 'OS1 - Groups';
|
||||||
// preload spinner asset
|
// preload spinner asset
|
||||||
new Image().src = '/~landscape/img/Spinner.png';
|
new Image().src = '/~landscape/img/Spinner.png';
|
||||||
|
|
||||||
@ -121,8 +121,8 @@ export default class GroupsApp extends Component {
|
|||||||
const detail = Boolean(props.match.url.includes('/detail'));
|
const detail = Boolean(props.match.url.includes('/detail'));
|
||||||
const settings = Boolean(props.match.url.includes('/settings'));
|
const settings = Boolean(props.match.url.includes('/settings'));
|
||||||
|
|
||||||
const association = (associations[groupPath])
|
const association = (associations.contacts?.[groupPath])
|
||||||
? associations[groupPath]
|
? associations.contacts[groupPath]
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -152,6 +152,7 @@ export default class GroupsApp extends Component {
|
|||||||
group={group}
|
group={group}
|
||||||
activeDrawer={(detail || settings) ? 'detail' : 'contacts'}
|
activeDrawer={(detail || settings) ? 'detail' : 'contacts'}
|
||||||
settings={settings}
|
settings={settings}
|
||||||
|
associations={associations}
|
||||||
api={this.api}
|
api={this.api}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
@ -141,12 +141,10 @@ export class ContactCard extends Component {
|
|||||||
type: 'Saving to group'
|
type: 'Saving to group'
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
props.api
|
props.api.contactHook.edit(props.path, ship, {
|
||||||
.contactEdit(props.path, ship, {
|
avatar: {
|
||||||
avatar: {
|
url: state.avatarToSet
|
||||||
url: state.avatarToSet
|
}})
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.setState({ awaiting: false });
|
this.setState({ awaiting: false });
|
||||||
});
|
});
|
||||||
@ -163,8 +161,8 @@ export class ContactCard extends Component {
|
|||||||
|
|
||||||
if (hexTest && hexTest[1] !== currentColor && !props.share) {
|
if (hexTest && hexTest[1] !== currentColor && !props.share) {
|
||||||
this.setState({ awaiting: true, type: 'Saving to group' }, () => {
|
this.setState({ awaiting: true, type: 'Saving to group' }, () => {
|
||||||
props.api
|
props.api.contactHook.edit(
|
||||||
.contactEdit(props.path, `~${props.ship}`, { color: hexTest[1] })
|
props.path, `~${props.ship}`, { color: hexTest[1] })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.setState({ awaiting: false });
|
this.setState({ awaiting: false });
|
||||||
});
|
});
|
||||||
@ -182,8 +180,8 @@ export class ContactCard extends Component {
|
|||||||
const emailTestResult = emailTest.exec(state.emailToSet);
|
const emailTestResult = emailTest.exec(state.emailToSet);
|
||||||
if (emailTestResult) {
|
if (emailTestResult) {
|
||||||
this.setState({ awaiting: true, type: 'Saving to group' }, () => {
|
this.setState({ awaiting: true, type: 'Saving to group' }, () => {
|
||||||
props.api
|
props.api.contactHook.edit(
|
||||||
.contactEdit(props.path, ship, { email: state.emailToSet })
|
props.path, ship, { email: state.emailToSet })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.setState({ awaiting: false });
|
this.setState({ awaiting: false });
|
||||||
});
|
});
|
||||||
@ -199,8 +197,8 @@ export class ContactCard extends Component {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.setState({ awaiting: true, type: 'Saving to group' }, () => {
|
this.setState({ awaiting: true, type: 'Saving to group' }, () => {
|
||||||
props.api
|
props.api.contactHook.edit(
|
||||||
.contactEdit(props.path, ship, { nickname: state.nickNameToSet })
|
props.path, ship, { nickname: state.nickNameToSet })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.setState({ awaiting: false });
|
this.setState({ awaiting: false });
|
||||||
});
|
});
|
||||||
@ -216,8 +214,8 @@ export class ContactCard extends Component {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.setState({ awaiting: true, type: 'Saving to group' }, () => {
|
this.setState({ awaiting: true, type: 'Saving to group' }, () => {
|
||||||
props.api
|
props.api.contactHook.edit(
|
||||||
.contactEdit(props.path, ship, { notes: state.notesToSet })
|
props.path, ship, { notes: state.notesToSet })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.setState({ awaiting: false });
|
this.setState({ awaiting: false });
|
||||||
});
|
});
|
||||||
@ -234,8 +232,8 @@ export class ContactCard extends Component {
|
|||||||
const phoneTestResult = phoneTest.exec(state.phoneToSet);
|
const phoneTestResult = phoneTest.exec(state.phoneToSet);
|
||||||
if (phoneTestResult) {
|
if (phoneTestResult) {
|
||||||
this.setState({ awaiting: true, type: 'Saving to group' }, () => {
|
this.setState({ awaiting: true, type: 'Saving to group' }, () => {
|
||||||
props.api
|
props.api.contactHook.edit(
|
||||||
.contactEdit(props.path, ship, { phone: state.phoneToSet })
|
props.path, ship, { phone: state.phoneToSet })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.setState({ awaiting: false });
|
this.setState({ awaiting: false });
|
||||||
});
|
});
|
||||||
@ -253,8 +251,8 @@ export class ContactCard extends Component {
|
|||||||
const websiteTestResult = websiteTest.exec(state.websiteToSet);
|
const websiteTestResult = websiteTest.exec(state.websiteToSet);
|
||||||
if (websiteTestResult) {
|
if (websiteTestResult) {
|
||||||
this.setState({ awaiting: true, type: 'Saving to group' }, () => {
|
this.setState({ awaiting: true, type: 'Saving to group' }, () => {
|
||||||
props.api
|
props.api.contactHook.edit(
|
||||||
.contactEdit(props.path, ship, { website: state.websiteToSet })
|
props.path, ship, { website: state.websiteToSet })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.setState({ awaiting: false });
|
this.setState({ awaiting: false });
|
||||||
});
|
});
|
||||||
@ -266,9 +264,10 @@ export class ContactCard extends Component {
|
|||||||
this.setState(
|
this.setState(
|
||||||
{ emailToSet: '', awaiting: true, type: 'Removing from group' },
|
{ emailToSet: '', awaiting: true, type: 'Removing from group' },
|
||||||
() => {
|
() => {
|
||||||
props.api.contactEdit(props.path, ship, { email: '' }).then(() => {
|
props.api.contactHook.edit(props.path, ship, { email: '' })
|
||||||
this.setState({ awaiting: false });
|
.then(() => {
|
||||||
});
|
this.setState({ awaiting: false });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
@ -277,9 +276,10 @@ export class ContactCard extends Component {
|
|||||||
this.setState(
|
this.setState(
|
||||||
{ nicknameToSet: '', awaiting: true, type: 'Removing from group' },
|
{ nicknameToSet: '', awaiting: true, type: 'Removing from group' },
|
||||||
() => {
|
() => {
|
||||||
props.api.contactEdit(props.path, ship, { nickname: '' }).then(() => {
|
props.api.contactHook.edit(props.path, ship, { nickname: '' })
|
||||||
this.setState({ awaiting: false });
|
.then(() => {
|
||||||
});
|
this.setState({ awaiting: false });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
@ -288,7 +288,7 @@ export class ContactCard extends Component {
|
|||||||
this.setState(
|
this.setState(
|
||||||
{ phoneToSet: '', awaiting: true, type: 'Removing from group' },
|
{ phoneToSet: '', awaiting: true, type: 'Removing from group' },
|
||||||
() => {
|
() => {
|
||||||
props.api.contactEdit(props.path, ship, { phone: '' }).then(() => {
|
props.api.contactHook.edit(props.path, ship, { phone: '' }).then(() => {
|
||||||
this.setState({ awaiting: false });
|
this.setState({ awaiting: false });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -299,7 +299,7 @@ export class ContactCard extends Component {
|
|||||||
this.setState(
|
this.setState(
|
||||||
{ websiteToSet: '', awaiting: true, type: 'Removing from group' },
|
{ websiteToSet: '', awaiting: true, type: 'Removing from group' },
|
||||||
() => {
|
() => {
|
||||||
props.api.contactEdit(props.path, ship, { website: '' }).then(() => {
|
props.api.contactHook.edit(props.path, ship, { website: '' }).then(() => {
|
||||||
this.setState({ awaiting: false });
|
this.setState({ awaiting: false });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -314,7 +314,7 @@ export class ContactCard extends Component {
|
|||||||
type: 'Removing from group'
|
type: 'Removing from group'
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
props.api.contactEdit(props.path, ship, { avatar: null }).then(() => {
|
props.api.contactHook.edit(props.path, ship, { avatar: null }).then(() => {
|
||||||
this.setState({ awaiting: false });
|
this.setState({ awaiting: false });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -325,7 +325,7 @@ export class ContactCard extends Component {
|
|||||||
this.setState(
|
this.setState(
|
||||||
{ notesToSet: '', awaiting: true, type: 'Removing from group' },
|
{ notesToSet: '', awaiting: true, type: 'Removing from group' },
|
||||||
() => {
|
() => {
|
||||||
props.api.contactEdit(props.path, ship, { notes: '' }).then(() => {
|
props.api.contactHook.edit(props.path, ship, { notes: '' }).then(() => {
|
||||||
this.setState({ awaiting: false });
|
this.setState({ awaiting: false });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -519,9 +519,10 @@ export class ContactCard extends Component {
|
|||||||
key={'avatar' + currentColor}
|
key={'avatar' + currentColor}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className="tl mt4 mb4 w-auto ml-auto mr-auto"
|
className="tc mt4 mb4 w-auto ml-auto mr-auto"
|
||||||
style={{ width: 'fit-content' }}
|
style={{ width: 'fit-content' }}
|
||||||
>
|
>
|
||||||
|
<div className="tl dib">
|
||||||
<p className="f9 gray2 lh-copy">Sigil Color</p>
|
<p className="f9 gray2 lh-copy">Sigil Color</p>
|
||||||
<textarea
|
<textarea
|
||||||
className={
|
className={
|
||||||
@ -543,6 +544,7 @@ export class ContactCard extends Component {
|
|||||||
width: 114
|
width: 114
|
||||||
}}
|
}}
|
||||||
></textarea>
|
></textarea>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-100 pt8 pb8 lh-copy tl">
|
<div className="w-100 pt8 pb8 lh-copy tl">
|
||||||
<p className="f9 gray2">Ship Name</p>
|
<p className="f9 gray2">Ship Name</p>
|
||||||
|
@ -99,7 +99,7 @@ export class ContactSidebar extends Component {
|
|||||||
style={{ paddingTop: 6 }}
|
style={{ paddingTop: 6 }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.setState({ awaiting: true }, (() => {
|
this.setState({ awaiting: true }, (() => {
|
||||||
props.api.groupRemove(props.path, [`~${member}`])
|
props.api.group.remove(props.path, [`~${member}`])
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.setState({ awaiting: false });
|
this.setState({ awaiting: false });
|
||||||
});
|
});
|
||||||
|
@ -18,11 +18,10 @@ export class GroupDetail extends Component {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { props } = this;
|
const { props } = this;
|
||||||
const channelPath = `${props.path}/contacts${props.path}`;
|
if (props.association.metadata) {
|
||||||
if ((props.association) && (props.association[channelPath])) {
|
|
||||||
this.setState({
|
this.setState({
|
||||||
title: props.association[channelPath].metadata.title,
|
title: props.association.metadata.title,
|
||||||
description: props.association[channelPath].metadata.description
|
description: props.association.metadata.description
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -30,11 +29,10 @@ export class GroupDetail extends Component {
|
|||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
const { props } = this;
|
const { props } = this;
|
||||||
if (prevProps !== this.props) {
|
if (prevProps !== this.props) {
|
||||||
const channelPath = `${props.path}/contacts${props.path}`;
|
if (props.association.metadata) {
|
||||||
if ((props.association) && (props.association[channelPath])) {
|
|
||||||
this.setState({
|
this.setState({
|
||||||
title: props.association[channelPath].metadata.title,
|
title: props.association.metadata.title,
|
||||||
description: props.association[channelPath].metadata.description
|
description: props.association.metadata.description
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,78 +52,74 @@ export class GroupDetail extends Component {
|
|||||||
const responsiveClass =
|
const responsiveClass =
|
||||||
props.activeDrawer === 'detail' ? 'db ' : 'dn db-ns ';
|
props.activeDrawer === 'detail' ? 'db ' : 'dn db-ns ';
|
||||||
|
|
||||||
const isEmpty = (Object.keys(props.association).length === 0) ||
|
let channelList = [];
|
||||||
((Object.keys(props.association).length === 1) &&
|
|
||||||
(Object.keys(props.association)[0].includes('contacts')));
|
|
||||||
|
|
||||||
let channelList = (<div />);
|
Object.keys(props.associations).filter((app) => {
|
||||||
|
return app !== 'contacts';
|
||||||
|
}).map((app) => {
|
||||||
|
Object.keys(props.associations[app]).filter((channel) => {
|
||||||
|
return props.associations[app][channel]['group-path'] === props.association['group-path'];
|
||||||
|
})
|
||||||
|
.map((channel) => {
|
||||||
|
const channelObj = props.associations[app][channel];
|
||||||
|
const title =
|
||||||
|
channelObj.metadata?.title || channelObj['app-path'] || '';
|
||||||
|
|
||||||
channelList = Object.keys(props.association).sort((a, b) => {
|
const color = uxToHex(channelObj.metadata?.color) || '000000';
|
||||||
const aChannel = props.association[a];
|
const channelPath = channelObj['app-path'];
|
||||||
const bChannel = props.association[b];
|
const link = `/~${app}/join${channelPath}`;
|
||||||
|
return(
|
||||||
const aTitle = aChannel.metadata.title || a;
|
channelList.push({
|
||||||
const bTitle = bChannel.metadata.title || b;
|
title: title,
|
||||||
|
color: color,
|
||||||
return aTitle.toLowerCase().localeCompare(bTitle.toLowerCase());
|
app: app.charAt(0).toUpperCase() + app.slice(1),
|
||||||
}).map((key) => {
|
link: link
|
||||||
const channel = props.association[key];
|
})
|
||||||
if (!('metadata' in channel)) {
|
);
|
||||||
return <div key={channel} />;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (channel['app-name'] === 'contacts') {
|
|
||||||
return <div key={channel} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const title = channel.metadata.title || channel['app-path'] || '';
|
|
||||||
const color = uxToHex(channel.metadata.color) || '000000';
|
|
||||||
let app = channel['app-name'] || 'Unknown';
|
|
||||||
const channelPath = channel['app-path'];
|
|
||||||
const link = `/~${app}/join${channelPath}`;
|
|
||||||
app = app.charAt(0).toUpperCase() + app.slice(1);
|
|
||||||
|
|
||||||
const overlay = {
|
|
||||||
r: parseInt(color.slice(0, 2), 16),
|
|
||||||
g: parseInt(color.slice(2, 4), 16),
|
|
||||||
b: parseInt(color.slice(4, 6), 16)
|
|
||||||
};
|
|
||||||
|
|
||||||
const tile = (app === 'Unknown')
|
|
||||||
? <div className="dib ba pa1" style={{
|
|
||||||
backgroundColor: `#${color}`,
|
|
||||||
borderColor: `#${color}`,
|
|
||||||
height: 24,
|
|
||||||
width: 24 }}
|
|
||||||
/>
|
|
||||||
: <div className="ba" style={{
|
|
||||||
borderColor: `#${color}`,
|
|
||||||
backgroundColor: `rgba(${overlay.r}, ${overlay.g}, ${overlay.b}, 0.25)`
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src={`/~groups/img/${app}.png`}
|
|
||||||
className="dib invert-d pa1 v-mid"
|
|
||||||
style={{ height: 26, width: 26 }}
|
|
||||||
/>
|
|
||||||
</div>;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<li key={channelPath} className="f9 list flex pv1 w-100">
|
|
||||||
{tile}
|
|
||||||
<div className="flex flex-column flex-auto">
|
|
||||||
<p className="f9 inter ml2 w-100">{title}</p>
|
|
||||||
<p className="f9 inter ml2 w-100">
|
|
||||||
<span className="f9 di mr2 inter">{app}</span>
|
|
||||||
<Link className="f9 di green2" to={link}>
|
|
||||||
Open
|
|
||||||
</Link>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isEmpty = (Boolean(channelList.length === 0));
|
||||||
|
|
||||||
|
if (channelList.length === 0) {
|
||||||
|
channelList = <div />;
|
||||||
|
} else {
|
||||||
|
channelList = channelList.sort((a, b) => {
|
||||||
|
return a.title.toLowerCase().localeCompare(b.title.toLowerCase());
|
||||||
|
}).map((each) => {
|
||||||
|
const overlay = {
|
||||||
|
r: parseInt(each.color.slice(0, 2), 16),
|
||||||
|
g: parseInt(each.color.slice(2, 4), 16),
|
||||||
|
b: parseInt(each.color.slice(4, 6), 16)
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li key={each.link} className="f9 list flex pv1 w-100">
|
||||||
|
<div className="ba" style={{
|
||||||
|
borderColor: `#${each.color}`,
|
||||||
|
backgroundColor: `rgba(${overlay.r}, ${overlay.g}, ${overlay.b}, 0.25)`
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={`/~landscape/img/${each.app}.png`}
|
||||||
|
className="dib invert-d pa1 v-mid"
|
||||||
|
style={{ height: 26, width: 26 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-column flex-auto">
|
||||||
|
<p className="f9 inter ml2 w-100">{each.title}</p>
|
||||||
|
<p className="f9 inter ml2 w-100">
|
||||||
|
<span className="f9 di mr2 inter">{each.app}</span>
|
||||||
|
<Link className="f9 di green2" to={each.link}>
|
||||||
|
Open
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let backLink = props.location.pathname;
|
let backLink = props.location.pathname;
|
||||||
backLink = backLink.slice(0, props.location.pathname.indexOf('/detail'));
|
backLink = backLink.slice(0, props.location.pathname.indexOf('/detail'));
|
||||||
|
|
||||||
@ -139,13 +133,12 @@ export class GroupDetail extends Component {
|
|||||||
|
|
||||||
let title = props.path.substr(1);
|
let title = props.path.substr(1);
|
||||||
let description = '';
|
let description = '';
|
||||||
const channel = `${props.path}/contacts${props.path}`;
|
if (props.association?.metadata) {
|
||||||
if ((props.association) && (props.association[channel])) {
|
title = (props.association.metadata.title !== '')
|
||||||
title = (props.association[channel].metadata.title !== '')
|
? props.association.metadata.title
|
||||||
? props.association[channel].metadata.title
|
|
||||||
: props.path.substr(1);
|
: props.path.substr(1);
|
||||||
description = (props.association[channel].metadata.description !== '')
|
description = (props.association.metadata.description !== '')
|
||||||
? props.association[channel].metadata.description
|
? props.association.metadata.description
|
||||||
: '';
|
: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,10 +174,7 @@ export class GroupDetail extends Component {
|
|||||||
|
|
||||||
const groupOwner = (deSig(props.match.params.ship) === window.ship);
|
const groupOwner = (deSig(props.match.params.ship) === window.ship);
|
||||||
|
|
||||||
const channelPath = `${props.path}/contacts${props.path}`;
|
const association = props.association;
|
||||||
|
|
||||||
const association = ((props.association) && (props.association[channelPath]))
|
|
||||||
? props.association[channelPath] : {};
|
|
||||||
|
|
||||||
const deleteButtonClasses = (groupOwner) ? 'b--red2 red2 pointer bg-gray0-d' : 'b--gray3 gray3 bg-gray0-d c-default';
|
const deleteButtonClasses = (groupOwner) ? 'b--red2 red2 pointer bg-gray0-d' : 'b--gray3 gray3 bg-gray0-d c-default';
|
||||||
|
|
||||||
@ -208,7 +198,7 @@ export class GroupDetail extends Component {
|
|||||||
onBlur={() => {
|
onBlur={() => {
|
||||||
if (groupOwner) {
|
if (groupOwner) {
|
||||||
this.setState({ awaiting: true }, (() => {
|
this.setState({ awaiting: true }, (() => {
|
||||||
props.api.metadataAdd(
|
props.api.metadata.add(
|
||||||
association['app-path'],
|
association['app-path'],
|
||||||
association['group-path'],
|
association['group-path'],
|
||||||
this.state.title,
|
this.state.title,
|
||||||
@ -237,7 +227,7 @@ export class GroupDetail extends Component {
|
|||||||
onBlur={() => {
|
onBlur={() => {
|
||||||
if (groupOwner) {
|
if (groupOwner) {
|
||||||
this.setState({ awaiting: true }, (() => {
|
this.setState({ awaiting: true }, (() => {
|
||||||
props.api.metadataAdd(
|
props.api.metadata.add(
|
||||||
association['app-path'],
|
association['app-path'],
|
||||||
association['group-path'],
|
association['group-path'],
|
||||||
association.metadata.title,
|
association.metadata.title,
|
||||||
|
@ -69,33 +69,23 @@ export class GroupSidebar extends Component {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const selectedPaths = selectedGroups.map(((e) => {
|
const selectedPaths = selectedGroups.map(((e) => {
|
||||||
return e[0];
|
return e[0];
|
||||||
}));
|
}));
|
||||||
return (selectedPaths.includes(path));
|
return (selectedPaths.includes(path));
|
||||||
})
|
})
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
let aName = a.substr(1);
|
let aName = a.substr(1);
|
||||||
let bName = b.substr(1);
|
let bName = b.substr(1);
|
||||||
const aChannel = `${a}/contacts${a}`;
|
if (props.associations.contacts?.[a]?.metadata) {
|
||||||
const bChannel = `${b}/contacts${b}`;
|
|
||||||
if (
|
|
||||||
props.associations[a] &&
|
|
||||||
props.associations[a][aChannel] &&
|
|
||||||
props.associations[a][aChannel].metadata
|
|
||||||
) {
|
|
||||||
aName =
|
aName =
|
||||||
props.associations[a][aChannel].metadata.title !== ''
|
props.associations.contacts[a].metadata.title !== ''
|
||||||
? props.associations[a][aChannel].metadata.title
|
? props.associations.contacts[a].metadata.title
|
||||||
: a.substr(1);
|
: a.substr(1);
|
||||||
}
|
}
|
||||||
if (
|
if (props.associations.contacts?.[b]?.metadata) {
|
||||||
props.associations[b] &&
|
|
||||||
props.associations[b][bChannel] &&
|
|
||||||
props.associations[b][bChannel].metadata
|
|
||||||
) {
|
|
||||||
bName =
|
bName =
|
||||||
props.associations[b][bChannel].metadata.title !== ''
|
props.associations.contacts[b].metadata.title !== ''
|
||||||
? props.associations[b][bChannel].metadata.title
|
? props.associations.contacts[b].metadata.title
|
||||||
: b.substr(1);
|
: b.substr(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,15 +94,10 @@ export class GroupSidebar extends Component {
|
|||||||
.map((path) => {
|
.map((path) => {
|
||||||
let name = path.substr(1);
|
let name = path.substr(1);
|
||||||
const selected = props.selected === path;
|
const selected = props.selected === path;
|
||||||
const groupChannel = `${path}/contacts${path}`;
|
if (props.associations.contacts?.[path]?.metadata) {
|
||||||
if (
|
|
||||||
props.associations[path] &&
|
|
||||||
props.associations[path][groupChannel] &&
|
|
||||||
props.associations[path][groupChannel].metadata
|
|
||||||
) {
|
|
||||||
name =
|
name =
|
||||||
props.associations[path][groupChannel].metadata.title !== ''
|
props.associations.contacts[path].metadata.title !== ''
|
||||||
? props.associations[path][groupChannel].metadata.title
|
? props.associations.contacts[path].metadata.title
|
||||||
: path.substr(1);
|
: path.substr(1);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
@ -23,7 +23,7 @@ export default class LaunchApp extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
window.title = 'OS1 - Home';
|
document.title = 'OS1 - Home';
|
||||||
// preload spinner asset
|
// preload spinner asset
|
||||||
new Image().src = '/~landscape/img/Spinner.png';
|
new Image().src = '/~landscape/img/Spinner.png';
|
||||||
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classnames from 'classnames';
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import SunCalc from 'suncalc';
|
import SunCalc from 'suncalc';
|
||||||
|
|
||||||
import Tile from './tile';
|
import Tile from './tile';
|
||||||
|
|
||||||
const outerSize = 124; //tile size
|
const innerSize = 124; // clock size
|
||||||
const innerSize = 124; //clock size
|
|
||||||
|
|
||||||
//polar to cartesian
|
// polar to cartesian
|
||||||
// var ptc = function(r, theta) {
|
// var ptc = function(r, theta) {
|
||||||
// return {
|
// return {
|
||||||
// x: r * Math.cos(theta),
|
// x: r * Math.cos(theta),
|
||||||
@ -16,77 +14,72 @@ const innerSize = 124; //clock size
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let text = "#000000", background = "#ffffff";
|
let text = '#000000', background = '#ffffff';
|
||||||
|
|
||||||
let dark = window.matchMedia('(prefers-color-scheme: dark)');
|
const dark = window.matchMedia('(prefers-color-scheme: dark)');
|
||||||
|
|
||||||
if (dark.matches) {
|
if (dark.matches) {
|
||||||
text = "#7f7f7f";
|
text = '#7f7f7f';
|
||||||
background = "#333";
|
background = '#333';
|
||||||
}
|
}
|
||||||
|
|
||||||
function darkColors(dark) {
|
function darkColors(dark) {
|
||||||
if (dark.matches) {
|
if (dark.matches) {
|
||||||
text = "#7f7f7f";
|
text = '#7f7f7f';
|
||||||
background = "#333";
|
background = '#333';
|
||||||
} else {
|
} else {
|
||||||
text = "#000000";
|
text = '#000000';
|
||||||
background = "#ffffff"
|
background = '#ffffff';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dark.addListener(darkColors);
|
dark.addListener(darkColors);
|
||||||
|
|
||||||
|
|
||||||
const toRelativeTime = (date, referenceTime, unit) => moment(date)
|
const toRelativeTime = (date, referenceTime, unit) => moment(date)
|
||||||
.diff(referenceTime, unit)
|
.diff(referenceTime, unit);
|
||||||
|
|
||||||
const minsToDegs = (mins) => {
|
const minsToDegs = (mins) => {
|
||||||
// 1440 = total minutes in an earth day
|
// 1440 = total minutes in an earth day
|
||||||
return (mins / 1440) * 360
|
return (mins / 1440) * 360;
|
||||||
}
|
};
|
||||||
|
|
||||||
const clockwise = (deg, delta) => deg + delta
|
const splitArc = (start, end) => end + ((start - end) * 0.5);
|
||||||
|
|
||||||
const anticlockwise = (deg, delta) => deg - delta
|
|
||||||
|
|
||||||
const splitArc = (start, end) => end + ((start - end) * 0.5)
|
|
||||||
|
|
||||||
const isOdd = n => Math.abs(n % 2) == 1;
|
const isOdd = n => Math.abs(n % 2) == 1;
|
||||||
|
|
||||||
const radToDeg = (rad) => rad * (180 / Math.PI);
|
const radToDeg = rad => rad * (180 / Math.PI);
|
||||||
|
|
||||||
const degToRad = (deg) => deg * (Math.PI / 180);
|
const degToRad = deg => deg * (Math.PI / 180);
|
||||||
|
|
||||||
const convert = (date, referenceTime) => {
|
const convert = (date, referenceTime) => {
|
||||||
return minsToDegs(toRelativeTime(date, referenceTime, 'minutes'))
|
return minsToDegs(toRelativeTime(date, referenceTime, 'minutes'));
|
||||||
}
|
};
|
||||||
|
|
||||||
const circle = (ctx, x, y, r, from, to, fill) => {
|
const circle = (ctx, x, y, r, from, to, fill) => {
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc( x, y, r, from, to, );
|
ctx.arc( x, y, r, from, to );
|
||||||
ctx.strokeStyle = 'rgba(0,0,0,0)';
|
ctx.strokeStyle = 'rgba(0,0,0,0)';
|
||||||
ctx.fillStyle = fill || 'rgba(0,0,0,0)';
|
ctx.fillStyle = fill || 'rgba(0,0,0,0)';
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
}
|
};
|
||||||
|
|
||||||
const circleOutline = (ctx, x, y, r, from, to, stroke, lineWidth) => {
|
const circleOutline = (ctx, x, y, r, from, to, stroke, lineWidth) => {
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc( x, y, r, from, to, );
|
ctx.arc( x, y, r, from, to );
|
||||||
ctx.fillStyle = 'rgba(0,0,0,0)';
|
ctx.fillStyle = 'rgba(0,0,0,0)';
|
||||||
ctx.lineWidth = lineWidth;
|
ctx.lineWidth = lineWidth;
|
||||||
ctx.strokeStyle = stroke || 'rgba(0,0,0,0)';
|
ctx.strokeStyle = stroke || 'rgba(0,0,0,0)';
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
}
|
};
|
||||||
|
|
||||||
const arc = (ctx, x, y, r, from, to, fill) => {
|
const arc = (ctx, x, y, r, from, to, fill) => {
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc( x, y, r, from, to, );
|
ctx.arc( x, y, r, from, to );
|
||||||
ctx.fillStyle = 'rgba(0,0,0,0)';
|
ctx.fillStyle = 'rgba(0,0,0,0)';
|
||||||
ctx.lineWidth = r * 2;
|
ctx.lineWidth = r * 2;
|
||||||
ctx.strokeStyle = fill || 'rgba(0,0,0,0)';
|
ctx.strokeStyle = fill || 'rgba(0,0,0,0)';
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
}
|
};
|
||||||
|
|
||||||
const degArc = (ctx, x, y, r, from, to, fill) => {
|
const degArc = (ctx, x, y, r, from, to, fill) => {
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
@ -95,17 +88,16 @@ const degArc = (ctx, x, y, r, from, to, fill) => {
|
|||||||
ctx.lineWidth = r * 2;
|
ctx.lineWidth = r * 2;
|
||||||
ctx.strokeStyle = fill || 'rgba(0,0,0,0)';
|
ctx.strokeStyle = fill || 'rgba(0,0,0,0)';
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
}
|
};
|
||||||
|
|
||||||
class Clock extends React.Component {
|
class Clock extends React.Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.animate = this.animate.bind(this);
|
this.animate = this.animate.bind(this);
|
||||||
this.canvasRef = React.createRef();
|
this.canvasRef = React.createRef();
|
||||||
this.canvas = null;
|
this.canvas = null;
|
||||||
this.angle = 0;
|
this.angle = 0;
|
||||||
this.referenceTime = moment().startOf('day').subtract(6, 'hours')
|
this.referenceTime = moment().startOf('day').subtract(6, 'hours');
|
||||||
this.state = {
|
this.state = {
|
||||||
lat: 0,
|
lat: 0,
|
||||||
lon: 0,
|
lon: 0,
|
||||||
@ -119,23 +111,22 @@ class Clock extends React.Component {
|
|||||||
night: 0,
|
night: 0,
|
||||||
nightEnd: 0,
|
nightEnd: 0,
|
||||||
nauticalDawn: 0,
|
nauticalDawn: 0,
|
||||||
nauticalDusk: 0,
|
nauticalDusk: 0
|
||||||
// sunriseStartTime = 1509967519,
|
// sunriseStartTime = 1509967519,
|
||||||
// sunriseEndTime = 2500 + 1509967519,
|
// sunriseEndTime = 2500 + 1509967519,
|
||||||
// sunsetStartTime = 1510003982,
|
// sunsetStartTime = 1510003982,
|
||||||
// sunsetEndTime
|
// sunsetEndTime
|
||||||
// moonPhase = 0.59,
|
// moonPhase = 0.59,
|
||||||
}
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initGeolocation() {
|
initGeolocation() {
|
||||||
if (typeof this.props.data === 'string') {
|
if (typeof this.props.data === 'string') {
|
||||||
const latlon = this.props.data.split(',')
|
const latlon = this.props.data.split(',');
|
||||||
const lat = latlon[0]
|
const lat = latlon[0];
|
||||||
const lon = latlon[1]
|
const lon = latlon[1];
|
||||||
|
|
||||||
const suncalc = SunCalc.getTimes(new Date(), lat, lon)
|
const suncalc = SunCalc.getTimes(new Date(), lat, lon);
|
||||||
|
|
||||||
const convertedSunCalc = {
|
const convertedSunCalc = {
|
||||||
sunset: convert(suncalc.sunset, this.referenceTime),
|
sunset: convert(suncalc.sunset, this.referenceTime),
|
||||||
@ -147,25 +138,24 @@ class Clock extends React.Component {
|
|||||||
night: convert(suncalc.night, this.referenceTime),
|
night: convert(suncalc.night, this.referenceTime),
|
||||||
nightEnd: convert(suncalc.nightEnd, this.referenceTime),
|
nightEnd: convert(suncalc.nightEnd, this.referenceTime),
|
||||||
nauticalDawn: convert(suncalc.nauticalDawn, this.referenceTime),
|
nauticalDawn: convert(suncalc.nauticalDawn, this.referenceTime),
|
||||||
nauticalDusk: convert(suncalc.nauticalDusk, this.referenceTime),
|
nauticalDusk: convert(suncalc.nauticalDusk, this.referenceTime)
|
||||||
}
|
};
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
lat,
|
lat,
|
||||||
lon,
|
lon,
|
||||||
...convertedSunCalc,
|
...convertedSunCalc,
|
||||||
geolocationSuccess: true,
|
geolocationSuccess: true
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if (prevProps !== this.props) {
|
if (prevProps !== this.props) {
|
||||||
this.initGeolocation()
|
this.initGeolocation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.canvas = initCanvas(
|
this.canvas = initCanvas(
|
||||||
this.canvasRef,
|
this.canvasRef,
|
||||||
@ -173,29 +163,27 @@ class Clock extends React.Component {
|
|||||||
4
|
4
|
||||||
);
|
);
|
||||||
|
|
||||||
this.initGeolocation()
|
this.initGeolocation();
|
||||||
this.animate()
|
this.animate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
animate() {
|
animate() {
|
||||||
window.setTimeout(() => window.requestAnimationFrame(this.animate), 1000)
|
window.setTimeout(() => window.requestAnimationFrame(this.animate), 1000);
|
||||||
|
|
||||||
const { state } = this
|
const { state } = this;
|
||||||
const time = new Date();
|
const time = new Date();
|
||||||
const ctx = this.canvas.getContext("2d");
|
const ctx = this.canvas.getContext('2d');
|
||||||
ctx.clearRect(0, 0, ctx.width, ctx.height);
|
ctx.clearRect(0, 0, ctx.width, ctx.height);
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
const ctr = innerSize / 2
|
const ctr = innerSize / 2;
|
||||||
|
|
||||||
// Sun+moon calculations
|
// Sun+moon calculations
|
||||||
const dd = 4
|
const cx = ctr;
|
||||||
var cx = ctr
|
const cy = ctr;
|
||||||
var cy = ctr
|
this.angle = degToRad(convert(time, this.referenceTime));
|
||||||
this.angle = degToRad(convert(time, this.referenceTime))
|
const newX = cx + (ctr - 15) * Math.cos(this.angle);
|
||||||
var newX = cx + (ctr - 15) * Math.cos(this.angle);
|
const newY = cy + (ctr - 15) * Math.sin(this.angle);
|
||||||
var newY = cy + (ctr - 15) * Math.sin(this.angle);
|
|
||||||
|
|
||||||
// Initial background
|
// Initial background
|
||||||
circle(
|
circle(
|
||||||
@ -206,7 +194,7 @@ class Clock extends React.Component {
|
|||||||
-1,
|
-1,
|
||||||
2 * Math.PI,
|
2 * Math.PI,
|
||||||
background
|
background
|
||||||
)
|
);
|
||||||
|
|
||||||
// Day
|
// Day
|
||||||
degArc(
|
degArc(
|
||||||
@ -276,7 +264,7 @@ class Clock extends React.Component {
|
|||||||
0,
|
0,
|
||||||
2 * Math.PI,
|
2 * Math.PI,
|
||||||
'#FCC440'
|
'#FCC440'
|
||||||
)
|
);
|
||||||
|
|
||||||
// Sun circle border
|
// Sun circle border
|
||||||
circleOutline(
|
circleOutline(
|
||||||
@ -299,7 +287,7 @@ class Clock extends React.Component {
|
|||||||
0,
|
0,
|
||||||
2 * Math.PI,
|
2 * Math.PI,
|
||||||
'#FFFFFF'
|
'#FFFFFF'
|
||||||
)
|
);
|
||||||
// Moon circle outline
|
// Moon circle outline
|
||||||
circleOutline(
|
circleOutline(
|
||||||
ctx,
|
ctx,
|
||||||
@ -357,7 +345,7 @@ class Clock extends React.Component {
|
|||||||
-1,
|
-1,
|
||||||
2 * Math.PI,
|
2 * Math.PI,
|
||||||
background
|
background
|
||||||
)
|
);
|
||||||
|
|
||||||
// Center white circle border
|
// Center white circle border
|
||||||
circleOutline(
|
circleOutline(
|
||||||
@ -374,26 +362,27 @@ class Clock extends React.Component {
|
|||||||
// Text for time and date
|
// Text for time and date
|
||||||
const timeText = isOdd(time.getSeconds())
|
const timeText = isOdd(time.getSeconds())
|
||||||
? moment().format('h mm A')
|
? moment().format('h mm A')
|
||||||
: moment().format('h:mm A')
|
: moment().format('h:mm A');
|
||||||
const dateText = moment().format('MMM Do')
|
const dateText = moment().format('MMM Do');
|
||||||
ctx.textAlign = 'center'
|
ctx.textAlign = 'center';
|
||||||
ctx.fillStyle = text
|
ctx.fillStyle = text;
|
||||||
ctx.font = '12px Inter'
|
ctx.font = '12px Inter';
|
||||||
ctx.fillText(timeText, ctr, ctr + 6 - 7)
|
ctx.fillText(timeText, ctr, ctr + 6 - 7);
|
||||||
ctx.fillStyle = text
|
ctx.fillStyle = text;
|
||||||
ctx.font = '12px Inter'
|
ctx.font = '12px Inter';
|
||||||
ctx.fillText(dateText, ctr, ctr + 6 + 7)
|
ctx.fillText(dateText, ctr, ctr + 6 + 7);
|
||||||
|
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <div style={{position:'relative'}}>
|
return <div style={{ position:'relative' }}>
|
||||||
<canvas
|
<canvas
|
||||||
style={{position:'absolute'}}
|
style={{ position:'absolute' }}
|
||||||
ref={ canvasRef => this.canvasRef = canvasRef }
|
ref={ canvasRef => this.canvasRef = canvasRef }
|
||||||
id="clock-canvas"/>
|
id="clock-canvas"
|
||||||
</div>
|
/>
|
||||||
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,27 +400,15 @@ export default class ClockTile extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let data = !!this.props.data ? this.props.data : {};
|
const data = this.props.data ? this.props.data : {};
|
||||||
return this.renderWrapper((
|
return this.renderWrapper((
|
||||||
<Clock data={data}/>
|
<Clock data={data} />
|
||||||
));
|
));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadImg = (base64, cb) => new Promise(resolve => {
|
|
||||||
const img = new Image();
|
|
||||||
img.onload = () => resolve(cb(img));
|
|
||||||
img.onerror = () => reject('Error loading image');
|
|
||||||
img.src = base64;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
const initCanvas = (canvas, size, ratio) => {
|
const initCanvas = (canvas, size, ratio) => {
|
||||||
const { x, y } = size;
|
const { x, y } = size;
|
||||||
let ctx = canvas.getContext('2d');
|
|
||||||
|
|
||||||
// let ratio = ctx.webkitBackingStorePixelRatio < 2
|
// let ratio = ctx.webkitBackingStorePixelRatio < 2
|
||||||
// ? window.devicePixelRatio
|
// ? window.devicePixelRatio
|
||||||
// : 1;
|
// : 1;
|
||||||
@ -439,7 +416,6 @@ const initCanvas = (canvas, size, ratio) => {
|
|||||||
// default for high print resolution.
|
// default for high print resolution.
|
||||||
// ratio = ratio * resMult;
|
// ratio = ratio * resMult;
|
||||||
|
|
||||||
|
|
||||||
canvas.width = x * ratio;
|
canvas.width = x * ratio;
|
||||||
canvas.height = y * ratio;
|
canvas.height = y * ratio;
|
||||||
canvas.style.width = x + 'px';
|
canvas.style.width = x + 'px';
|
||||||
@ -448,5 +424,5 @@ const initCanvas = (canvas, size, ratio) => {
|
|||||||
canvas.getContext('2d').scale(ratio, ratio);
|
canvas.getContext('2d').scale(ratio, ratio);
|
||||||
|
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classnames from 'classnames';
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import Tile from './tile';
|
import Tile from './tile';
|
||||||
@ -13,121 +12,123 @@ export default class WeatherTile extends React.Component {
|
|||||||
error: false
|
error: false
|
||||||
};
|
};
|
||||||
|
|
||||||
let api = props.api;
|
this.api = props.api;
|
||||||
}
|
}
|
||||||
// geolocation and manual input functions
|
// geolocation and manual input functions
|
||||||
locationSubmit() {
|
locationSubmit() {
|
||||||
navigator.geolocation.getCurrentPosition((res) => {
|
navigator.geolocation.getCurrentPosition((res) => {
|
||||||
let latlng = `${res.coords.latitude},${res.coords.longitude}`;
|
const latlng = `${res.coords.latitude},${res.coords.longitude}`;
|
||||||
this.setState({
|
this.setState({
|
||||||
latlng
|
latlng
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}, { maximumAge: Infinity, timeout: 10000 });
|
}, { maximumAge: Infinity, timeout: 10000 });
|
||||||
api.action("clock", "json", latlng);
|
// this.api.clock.action(latlng);
|
||||||
api.action('weather', 'json', latlng);
|
this.api.weather.action(latlng);
|
||||||
this.setState({ manualEntry: !this.state.manualEntry });
|
this.setState({ manualEntry: !this.state.manualEntry });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
manualLocationSubmit() {
|
manualLocationSubmit() {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let gpsInput = document.getElementById('gps');
|
const gpsInput = document.getElementById('gps');
|
||||||
let latlngNoSpace = gpsInput.value.replace(/\s+/g, '');
|
const latlngNoSpace = gpsInput.value.replace(/\s+/g, '');
|
||||||
let latlngParse = /-?[0-9]+(?:\.[0-9]*)?,-?[0-9]+(?:\.[0-9]*)?/g;
|
const latlngParse = /-?[0-9]+(?:\.[0-9]*)?,-?[0-9]+(?:\.[0-9]*)?/g;
|
||||||
if (latlngParse.test(latlngNoSpace)) {
|
if (latlngParse.test(latlngNoSpace)) {
|
||||||
let latlng = latlngNoSpace;
|
const latlng = latlngNoSpace;
|
||||||
this.setState({latlng}, (err) => {console.log(err)}, {maximumAge: Infinity, timeout: 10000});
|
this.setState({ latlng }, (err) => {
|
||||||
api.action("clock", "json", latlng);
|
console.log(err);
|
||||||
api.action('weather', 'json', latlng);
|
}, { maximumAge: Infinity, timeout: 10000 });
|
||||||
this.setState({manualEntry: !this.state.manualEntry});
|
// this.api.clock.action(latlng);
|
||||||
}
|
this.api.weather.action(latlng);
|
||||||
else {
|
this.setState({ manualEntry: !this.state.manualEntry });
|
||||||
this.setState({error: true});
|
} else {
|
||||||
|
this.setState({ error: true });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// set appearance based on weather
|
// set appearance based on weather
|
||||||
setColors(data) {
|
setColors(data) {
|
||||||
let weatherStyle = {
|
let weatherStyle = {
|
||||||
gradient1: "",
|
gradient1: '',
|
||||||
gradient2: "",
|
gradient2: '',
|
||||||
text: ""
|
text: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (data.daily.icon) {
|
switch (data.daily.icon) {
|
||||||
case "clear-day":
|
case 'clear-day':
|
||||||
weatherStyle = {
|
weatherStyle = {
|
||||||
gradient1: "#A5CEF0", gradient2: "#FEF4E0", text: "black"
|
gradient1: '#A5CEF0', gradient2: '#FEF4E0', text: 'black'
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "clear-night":
|
|
||||||
weatherStyle = {
|
|
||||||
gradient1: "#56668e", gradient2: "#000080", text: "white"
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "rain":
|
|
||||||
weatherStyle = {
|
|
||||||
gradient1: "#b1b2b3", gradient2: "#b0c7ff", text: "black"
|
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case "snow":
|
case 'clear-night':
|
||||||
weatherStyle = {
|
weatherStyle = {
|
||||||
gradient1: "#eee", gradient2: "#f9f9f9", text: "black"
|
gradient1: '#56668e', gradient2: '#000080', text: 'white'
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case "sleet":
|
case 'rain':
|
||||||
weatherStyle = {
|
weatherStyle = {
|
||||||
gradient1: "#eee", gradient2: "#f9f9f9", text: "black"
|
gradient1: '#b1b2b3', gradient2: '#b0c7ff', text: 'black'
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case "wind":
|
case 'snow':
|
||||||
weatherStyle = {
|
weatherStyle = {
|
||||||
gradient1: "#eee", gradient2: "#fff", text: "black"
|
gradient1: '#eee', gradient2: '#f9f9f9', text: 'black'
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case "fog":
|
case 'sleet':
|
||||||
weatherStyle = {
|
weatherStyle = {
|
||||||
gradient1: "#eee", gradient2: "#fff", text: "black"
|
gradient1: '#eee', gradient2: '#f9f9f9', text: 'black'
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case "cloudy":
|
case 'wind':
|
||||||
weatherStyle = {
|
weatherStyle = {
|
||||||
gradient1: "#eee", gradient2: "#b1b2b3", text: "black"
|
gradient1: '#eee', gradient2: '#fff', text: 'black'
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case "partly-cloudy-day":
|
case 'fog':
|
||||||
weatherStyle = {
|
weatherStyle = {
|
||||||
gradient1: "#fcc440", gradient2: "#b1b2b3", text: "black"
|
gradient1: '#eee', gradient2: '#fff', text: 'black'
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case "partly-cloudy-night":
|
case 'cloudy':
|
||||||
weatherStyle = {
|
weatherStyle = {
|
||||||
gradient1: "#7f7f7f", gradient2: "#56668e", text: "white"
|
gradient1: '#eee', gradient2: '#b1b2b3', text: 'black'
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 'partly-cloudy-day':
|
||||||
|
weatherStyle = {
|
||||||
|
gradient1: '#fcc440', gradient2: '#b1b2b3', text: 'black'
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 'partly-cloudy-night':
|
||||||
|
weatherStyle = {
|
||||||
|
gradient1: '#7f7f7f', gradient2: '#56668e', text: 'white'
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
weatherStyle = {
|
weatherStyle = {
|
||||||
gradient1: "white", gradient2: "white", text: "black"
|
gradient1: 'white', gradient2: 'white', text: 'black'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return weatherStyle;
|
return weatherStyle;
|
||||||
}
|
}
|
||||||
// all tile views
|
// all tile views
|
||||||
renderWrapper(child,
|
renderWrapper(child,
|
||||||
weatherStyle = { gradient1: "white", gradient2: "white", text: "black" }
|
weatherStyle = { gradient1: 'white', gradient2: 'white', text: 'black' }
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<Tile>
|
<Tile>
|
||||||
<div
|
<div
|
||||||
className={"relative " + weatherStyle.text}
|
className={'relative ' + weatherStyle.text}
|
||||||
style={{
|
style={{
|
||||||
width: 126,
|
width: 126,
|
||||||
height: 126,
|
height: 126,
|
||||||
background: `linear-gradient(135deg, ${weatherStyle.gradient1} 0%,` +
|
background: `linear-gradient(135deg, ${weatherStyle.gradient1} 0%,` +
|
||||||
`${weatherStyle.gradient2} 45%, ${weatherStyle.gradient2} 65%,` +
|
`${weatherStyle.gradient2} 45%, ${weatherStyle.gradient2} 65%,` +
|
||||||
`${weatherStyle.gradient1} 100%)`
|
`${weatherStyle.gradient1} 100%)`
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
{child}
|
{child}
|
||||||
</div>
|
</div>
|
||||||
</Tile>
|
</Tile>
|
||||||
@ -139,56 +140,65 @@ export default class WeatherTile extends React.Component {
|
|||||||
let error;
|
let error;
|
||||||
if (this.state.error === true) {
|
if (this.state.error === true) {
|
||||||
error = <p
|
error = <p
|
||||||
className="f9 red2 pt1">Please try again.
|
className="f9 red2 pt1"
|
||||||
</p>
|
>Please try again.
|
||||||
|
</p>;
|
||||||
}
|
}
|
||||||
if (location.protocol === "https:") {
|
if (location.protocol === 'https:') {
|
||||||
secureCheck = <a
|
secureCheck = <a
|
||||||
className="black white-d f9 absolute pointer"
|
className="black white-d f9 absolute pointer"
|
||||||
style={{right: 8, top: 8}}
|
style={{ right: 8, top: 8 }}
|
||||||
onClick={() => this.locationSubmit()}>Detect -></a>
|
onClick={() => this.locationSubmit()}
|
||||||
|
>Detect -></a>;
|
||||||
}
|
}
|
||||||
return this.renderWrapper(
|
return this.renderWrapper(
|
||||||
<div className={"pa2 w-100 h-100 bg-white bg-gray0-d black white-d " +
|
<div className={'pa2 w-100 h-100 bg-white bg-gray0-d black white-d ' +
|
||||||
"b--black b--gray1-d ba"}>
|
'b--black b--gray1-d ba'}
|
||||||
|
>
|
||||||
<a
|
<a
|
||||||
className="f9 black white-d pointer"
|
className="f9 black white-d pointer absolute"
|
||||||
|
style={{ top: 8 }}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
this.setState({ manualEntry: !this.state.manualEntry })
|
this.setState({ manualEntry: !this.state.manualEntry })
|
||||||
}>
|
}
|
||||||
|
>
|
||||||
<-
|
<-
|
||||||
</a>
|
</a>
|
||||||
{secureCheck}
|
{secureCheck}
|
||||||
<p className="f9 pt2">
|
<p className="f9 pt5">
|
||||||
Please enter your{" "}
|
Please enter your{' '}
|
||||||
<a
|
<a
|
||||||
className="black white-d"
|
className="black bb white-d"
|
||||||
href="https://latitudeandlongitude.org/"
|
href="https://latitudeandlongitude.org/"
|
||||||
target="_blank">
|
target="_blank"
|
||||||
|
>
|
||||||
latitude and longitude
|
latitude and longitude
|
||||||
</a>
|
</a>
|
||||||
.
|
.
|
||||||
</p>
|
</p>
|
||||||
{error}
|
{error}
|
||||||
<div className="absolute" style={{left: 8, bottom: 8}}>
|
<div className="absolute" style={{ left: 8, bottom: 8 }}>
|
||||||
<form className="flex" style={{marginBlockEnd: 0 }}>
|
<form className="flex" style={{ marginBlockEnd: 0 }}>
|
||||||
<input
|
<input
|
||||||
id="gps"
|
id="gps"
|
||||||
className="w-100 black white-d bg-transparent bn f9"
|
className="w-100 black white-d bg-transparent bn f9"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="29.558107, -95.089023"
|
placeholder="29.558107, -95.089023"
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === 'Enter') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.manualLocationSubmit(e.target.value);
|
this.manualLocationSubmit(e.target.value);
|
||||||
}}
|
}
|
||||||
}/>
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
<input
|
<input
|
||||||
className={"bg-transparent black white-d bn pointer " +
|
className={'bg-transparent black white-d bn pointer ' +
|
||||||
"f9 flex-shrink-0"}
|
'f9 flex-shrink-0 pr1'}
|
||||||
type="submit"
|
type="submit"
|
||||||
onClick={() => this.manualLocationSubmit()}
|
onClick={() => this.manualLocationSubmit()}
|
||||||
value="->"/>
|
value="->"
|
||||||
|
/>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -198,15 +208,18 @@ export default class WeatherTile extends React.Component {
|
|||||||
renderNoData() {
|
renderNoData() {
|
||||||
return this.renderWrapper((
|
return this.renderWrapper((
|
||||||
<div
|
<div
|
||||||
className={"pa2 w-100 h-100 b--black b--gray1-d ba " +
|
className={'pa2 w-100 h-100 b--black b--gray1-d ba ' +
|
||||||
"bg-white bg-gray0-d black white-d"}
|
'bg-white bg-gray0-d black white-d'}
|
||||||
onClick={() => this.setState({manualEntry: !this.state.manualEntry})}>
|
onClick={() => this.setState({ manualEntry: !this.state.manualEntry })}
|
||||||
|
>
|
||||||
<p className="f9 absolute"
|
<p className="f9 absolute"
|
||||||
style={{left: 8, top: 8}}>
|
style={{ left: 8, top: 8 }}
|
||||||
|
>
|
||||||
Weather
|
Weather
|
||||||
</p>
|
</p>
|
||||||
<p className="absolute w-100 flex-col f9"
|
<p className="absolute w-100 flex-col f9"
|
||||||
style={{bottom: 8, left: 8, cursor: "pointer"}}>
|
style={{ bottom: 8, left: 8, cursor: 'pointer' }}
|
||||||
|
>
|
||||||
-> Set location
|
-> Set location
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -214,14 +227,15 @@ export default class WeatherTile extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderWithData(data, weatherStyle) {
|
renderWithData(data, weatherStyle) {
|
||||||
let c = data.currently;
|
const c = data.currently;
|
||||||
let d = data.daily.data[0];
|
const d = data.daily.data[0];
|
||||||
|
|
||||||
let da = moment.unix(d.sunsetTime).format('h:mm a') || '';
|
const da = moment.unix(d.sunsetTime).format('h:mm a') || '';
|
||||||
|
|
||||||
return this.renderWrapper(
|
return this.renderWrapper(
|
||||||
<div className="w-100 h-100 b--black b--gray1-d ba"
|
<div className="w-100 h-100 b--black b--gray1-d ba"
|
||||||
style={{backdropFilter: "blur(80px)"}}>
|
style={{ backdropFilter: 'blur(80px)' }}
|
||||||
|
>
|
||||||
<p className="f9 absolute" style={{ left: 8, top: 8 }}>
|
<p className="f9 absolute" style={{ left: 8, top: 8 }}>
|
||||||
Weather
|
Weather
|
||||||
</p>
|
</p>
|
||||||
@ -230,7 +244,8 @@ export default class WeatherTile extends React.Component {
|
|||||||
style={{ right: 8, top: 8 }}
|
style={{ right: 8, top: 8 }}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
this.setState({ manualEntry: !this.state.manualEntry })
|
this.setState({ manualEntry: !this.state.manualEntry })
|
||||||
}>
|
}
|
||||||
|
>
|
||||||
->
|
->
|
||||||
</a>
|
</a>
|
||||||
<div className="w-100 absolute" style={{ left: 8, bottom: 8 }}>
|
<div className="w-100 absolute" style={{ left: 8, bottom: 8 }}>
|
||||||
@ -243,20 +258,19 @@ export default class WeatherTile extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let data = !!this.props.data ? this.props.data : {};
|
const data = this.props.data ? this.props.data : {};
|
||||||
|
|
||||||
if (this.state.manualEntry === true) {
|
if (this.state.manualEntry === true) {
|
||||||
return this.renderManualEntry();
|
return this.renderManualEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('currently' in data && 'daily' in data) {
|
if ('currently' in data && 'daily' in data) {
|
||||||
let weatherStyle = this.setColors(data);
|
const weatherStyle = this.setColors(data);
|
||||||
return this.renderWithData(data, weatherStyle);
|
return this.renderWithData(data, weatherStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.renderNoData();
|
return this.renderNoData();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.weatherTile = WeatherTile;
|
window.weatherTile = WeatherTile;
|
||||||
|
@ -13,14 +13,6 @@ p, h1, h2, h3, h4, h5, h6, a, input, textarea, button {
|
|||||||
font-family: Inter, sans-serif;
|
font-family: Inter, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:any-link {
|
|
||||||
color: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:-webkit-any-link {
|
|
||||||
color: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea, select, input, button { outline: none; }
|
textarea, select, input, button { outline: none; }
|
||||||
|
|
||||||
.c-default {
|
.c-default {
|
||||||
|
@ -29,7 +29,7 @@ export class LinksApp extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
window.title = 'OS1 - Groups';
|
document.title = 'OS1 - Links';
|
||||||
// preload spinner asset
|
// preload spinner asset
|
||||||
new Image().src = '/~landscape/img/Spinner.png';
|
new Image().src = '/~landscape/img/Spinner.png';
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ export class LinksApp extends Component {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if(totalUnseen !== this.totalUnseen) {
|
if(totalUnseen !== this.totalUnseen) {
|
||||||
document.title = totalUnseen !== 0 ? `Links - (${totalUnseen})` : 'Links';
|
document.title = totalUnseen !== 0 ? `OS1 - Links (${totalUnseen})` : 'OS1 - Links';
|
||||||
this.totalUnseen = totalUnseen;
|
this.totalUnseen = totalUnseen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ export class LinkItem extends Component {
|
|||||||
classes={(member ? 'mix-blend-diff' : '')}
|
classes={(member ? 'mix-blend-diff' : '')}
|
||||||
/>;
|
/>;
|
||||||
return (
|
return (
|
||||||
<div className="w-100 pv3 flex bg-white bg-gray0-d">
|
<div className="w-100 pv3 flex bg-white bg-gray0-d lh-solid">
|
||||||
{img}
|
{img}
|
||||||
<div className="flex flex-column ml2 flex-auto">
|
<div className="flex flex-column ml2 flex-auto">
|
||||||
<a href={props.url}
|
<a href={props.url}
|
||||||
@ -80,7 +80,7 @@ export class LinkItem extends Component {
|
|||||||
</p>
|
</p>
|
||||||
<span className="gray2 dib v-btm ml2 f8 flex-shrink-0">{hostname} ↗</span>
|
<span className="gray2 dib v-btm ml2 f8 flex-shrink-0">{hostname} ↗</span>
|
||||||
</a>
|
</a>
|
||||||
<div className="w-100 pt1">
|
<div className="w-100">
|
||||||
<span className={'f9 pr2 dib ' + mono}
|
<span className={'f9 pr2 dib ' + mono}
|
||||||
title={props.ship}
|
title={props.ship}
|
||||||
>
|
>
|
||||||
|
@ -30,20 +30,22 @@ export class LinkDetail extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
// if we have no preloaded data, and we aren't expecting it, get it
|
this.componentDidUpdate();
|
||||||
if (!this.state.data.title) {
|
|
||||||
this.props.api.getSubmission(
|
|
||||||
this.props.resourcePath, this.props.url, this.updateData.bind(this)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if (this.props.url !== prevProps.url) {
|
// if we have no preloaded data, and we aren't expecting it, get it
|
||||||
this.updateData(this.props.data);
|
if ((!this.state.data.title) && (this.props.api)) {
|
||||||
|
this.props.api?.getSubmission(
|
||||||
|
this.props.resourcePath, this.props.url, this.updateData.bind(this)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (prevProps.comments && prevProps.comments['0'] &&
|
if (prevProps) {
|
||||||
this.props.comments && this.props.comments['0']) {
|
if (this.props.url !== prevProps.url) {
|
||||||
|
this.updateData(this.props.data);
|
||||||
|
}
|
||||||
|
if (prevProps.comments && prevProps.comments['0'] &&
|
||||||
|
this.props.comments && this.props.comments['0']) {
|
||||||
const prevFirstComment = prevProps.comments['0'][0];
|
const prevFirstComment = prevProps.comments['0'][0];
|
||||||
const thisFirstComment = this.props.comments['0'][0];
|
const thisFirstComment = this.props.comments['0'][0];
|
||||||
if ((prevFirstComment && prevFirstComment.udon) &&
|
if ((prevFirstComment && prevFirstComment.udon) &&
|
||||||
@ -56,6 +58,7 @@ export class LinkDetail extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,14 +26,16 @@ export class Links extends Component {
|
|||||||
// and don't have links for it yet,
|
// and don't have links for it yet,
|
||||||
// or the links we have might not be complete,
|
// or the links we have might not be complete,
|
||||||
// request the links for that page.
|
// request the links for that page.
|
||||||
if ( (!prevProps ||
|
if ( ((!prevProps || // first load?
|
||||||
linkPage !== prevProps.page ||
|
linkPage !== prevProps.page || // already waiting on response?
|
||||||
this.props.resourcePath !== prevProps.resourcePath
|
this.props.resourcePath !== prevProps.resourcePath // new page?
|
||||||
) &&
|
) ||
|
||||||
!this.props.links[linkPage] ||
|
(prevProps.api !== this.props.api)) // api prop instantiated?
|
||||||
this.props.links.local[linkPage]
|
&&
|
||||||
|
!this.props.links[linkPage] || // don't have info?
|
||||||
|
this.props.links.local[linkPage] // waiting on post confirmation?
|
||||||
) {
|
) {
|
||||||
this.props.api.getPage(this.props.resourcePath, this.props.page);
|
this.props.api?.getPage(this.props.resourcePath, this.props.page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ export default class PublishApp extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
window.title = 'OS1 - Groups';
|
document.title = 'OS1 - Publish';
|
||||||
// preload spinner asset
|
// preload spinner asset
|
||||||
new Image().src = '/~landscape/img/Spinner.png';
|
new Image().src = '/~landscape/img/Spinner.png';
|
||||||
|
|
||||||
@ -59,7 +59,9 @@ export default class PublishApp extends React.Component {
|
|||||||
const associations = state.associations ? state.associations : { contacts: {} };
|
const associations = state.associations ? state.associations : { contacts: {} };
|
||||||
const selectedGroups = props.selectedGroups ? props.selectedGroups : [];
|
const selectedGroups = props.selectedGroups ? props.selectedGroups : [];
|
||||||
|
|
||||||
const unreadTotal = _.chain(state.notebooks)
|
const notebooks = state.notebooks ? state.notebooks : {};
|
||||||
|
|
||||||
|
const unreadTotal = _.chain(notebooks)
|
||||||
.values()
|
.values()
|
||||||
.map(_.values)
|
.map(_.values)
|
||||||
.flatten() // flatten into array of notebooks
|
.flatten() // flatten into array of notebooks
|
||||||
@ -68,7 +70,7 @@ export default class PublishApp extends React.Component {
|
|||||||
.value();
|
.value();
|
||||||
|
|
||||||
if (this.unreadTotal !== unreadTotal) {
|
if (this.unreadTotal !== unreadTotal) {
|
||||||
window.title = unreadTotal > 0 ? `Publish - (${unreadTotal})` : 'Publish';
|
document.title = unreadTotal > 0 ? `OS1 - Publish (${unreadTotal})` : 'OS1 - Publish';
|
||||||
this.unreadTotal = unreadTotal;
|
this.unreadTotal = unreadTotal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +85,7 @@ export default class PublishApp extends React.Component {
|
|||||||
rightPanelHide={true}
|
rightPanelHide={true}
|
||||||
sidebarShown={true}
|
sidebarShown={true}
|
||||||
invites={state.invites}
|
invites={state.invites}
|
||||||
notebooks={state.notebooks}
|
notebooks={notebooks}
|
||||||
associations={associations}
|
associations={associations}
|
||||||
selectedGroups={selectedGroups}
|
selectedGroups={selectedGroups}
|
||||||
contacts={contacts}
|
contacts={contacts}
|
||||||
@ -111,7 +113,7 @@ export default class PublishApp extends React.Component {
|
|||||||
rightPanelHide={false}
|
rightPanelHide={false}
|
||||||
sidebarShown={state.sidebarShown}
|
sidebarShown={state.sidebarShown}
|
||||||
invites={state.invites}
|
invites={state.invites}
|
||||||
notebooks={state.notebooks}
|
notebooks={notebooks}
|
||||||
associations={associations}
|
associations={associations}
|
||||||
selectedGroups={selectedGroups}
|
selectedGroups={selectedGroups}
|
||||||
contacts={contacts}
|
contacts={contacts}
|
||||||
@ -119,7 +121,7 @@ export default class PublishApp extends React.Component {
|
|||||||
>
|
>
|
||||||
<NewScreen
|
<NewScreen
|
||||||
associations={associations.contacts}
|
associations={associations.contacts}
|
||||||
notebooks={state.notebooks}
|
notebooks={notebooks}
|
||||||
groups={state.groups}
|
groups={state.groups}
|
||||||
contacts={contacts}
|
contacts={contacts}
|
||||||
api={this.api}
|
api={this.api}
|
||||||
@ -140,14 +142,14 @@ export default class PublishApp extends React.Component {
|
|||||||
rightPanelHide={false}
|
rightPanelHide={false}
|
||||||
sidebarShown={state.sidebarShown}
|
sidebarShown={state.sidebarShown}
|
||||||
invites={state.invites}
|
invites={state.invites}
|
||||||
notebooks={state.notebooks}
|
notebooks={notebooks}
|
||||||
associations={associations}
|
associations={associations}
|
||||||
selectedGroups={selectedGroups}
|
selectedGroups={selectedGroups}
|
||||||
contacts={contacts}
|
contacts={contacts}
|
||||||
api={this.api}
|
api={this.api}
|
||||||
>
|
>
|
||||||
<JoinScreen
|
<JoinScreen
|
||||||
notebooks={state.notebooks}
|
notebooks={notebooks}
|
||||||
ship={ship}
|
ship={ship}
|
||||||
notebook={notebook}
|
notebook={notebook}
|
||||||
api={this.api}
|
api={this.api}
|
||||||
@ -171,7 +173,7 @@ export default class PublishApp extends React.Component {
|
|||||||
const path = `${ship}/${notebook}`;
|
const path = `${ship}/${notebook}`;
|
||||||
|
|
||||||
const bookGroupPath =
|
const bookGroupPath =
|
||||||
state.notebooks[ship][notebook]['subscribers-group-path'];
|
notebooks?.[ship]?.[notebook]?.['subscribers-group-path'];
|
||||||
|
|
||||||
const notebookContacts = (bookGroupPath in contacts)
|
const notebookContacts = (bookGroupPath in contacts)
|
||||||
? contacts[bookGroupPath] : {};
|
? contacts[bookGroupPath] : {};
|
||||||
@ -184,7 +186,7 @@ export default class PublishApp extends React.Component {
|
|||||||
rightPanelHide={false}
|
rightPanelHide={false}
|
||||||
sidebarShown={state.sidebarShown}
|
sidebarShown={state.sidebarShown}
|
||||||
invites={state.invites}
|
invites={state.invites}
|
||||||
notebooks={state.notebooks}
|
notebooks={notebooks}
|
||||||
associations={associations}
|
associations={associations}
|
||||||
selectedGroups={selectedGroups}
|
selectedGroups={selectedGroups}
|
||||||
contacts={contacts}
|
contacts={contacts}
|
||||||
@ -192,7 +194,7 @@ export default class PublishApp extends React.Component {
|
|||||||
api={this.api}
|
api={this.api}
|
||||||
>
|
>
|
||||||
<NewPost
|
<NewPost
|
||||||
notebooks={state.notebooks}
|
notebooks={notebooks}
|
||||||
ship={ship}
|
ship={ship}
|
||||||
book={notebook}
|
book={notebook}
|
||||||
sidebarShown={state.sidebarShown}
|
sidebarShown={state.sidebarShown}
|
||||||
@ -210,7 +212,7 @@ export default class PublishApp extends React.Component {
|
|||||||
rightPanelHide={false}
|
rightPanelHide={false}
|
||||||
sidebarShown={state.sidebarShown}
|
sidebarShown={state.sidebarShown}
|
||||||
invites={state.invites}
|
invites={state.invites}
|
||||||
notebooks={state.notebooks}
|
notebooks={notebooks}
|
||||||
associations={associations}
|
associations={associations}
|
||||||
contacts={contacts}
|
contacts={contacts}
|
||||||
selectedGroups={selectedGroups}
|
selectedGroups={selectedGroups}
|
||||||
@ -218,7 +220,7 @@ export default class PublishApp extends React.Component {
|
|||||||
api={this.api}
|
api={this.api}
|
||||||
>
|
>
|
||||||
<Notebook
|
<Notebook
|
||||||
notebooks={state.notebooks}
|
notebooks={notebooks}
|
||||||
view={view}
|
view={view}
|
||||||
ship={ship}
|
ship={ship}
|
||||||
book={notebook}
|
book={notebook}
|
||||||
@ -247,7 +249,7 @@ export default class PublishApp extends React.Component {
|
|||||||
const popout = Boolean(props.match.params.popout) || false;
|
const popout = Boolean(props.match.params.popout) || false;
|
||||||
|
|
||||||
const bookGroupPath =
|
const bookGroupPath =
|
||||||
state.notebooks[ship][notebook]['subscribers-group-path'];
|
notebooks?.[ship]?.[notebook]?.['subscribers-group-path'];
|
||||||
const notebookContacts = (bookGroupPath in state.contacts)
|
const notebookContacts = (bookGroupPath in state.contacts)
|
||||||
? contacts[bookGroupPath] : {};
|
? contacts[bookGroupPath] : {};
|
||||||
|
|
||||||
@ -261,7 +263,7 @@ export default class PublishApp extends React.Component {
|
|||||||
rightPanelHide={false}
|
rightPanelHide={false}
|
||||||
sidebarShown={state.sidebarShown}
|
sidebarShown={state.sidebarShown}
|
||||||
invites={state.invites}
|
invites={state.invites}
|
||||||
notebooks={state.notebooks}
|
notebooks={notebooks}
|
||||||
selectedGroups={selectedGroups}
|
selectedGroups={selectedGroups}
|
||||||
associations={associations}
|
associations={associations}
|
||||||
contacts={contacts}
|
contacts={contacts}
|
||||||
@ -269,7 +271,7 @@ export default class PublishApp extends React.Component {
|
|||||||
api={this.api}
|
api={this.api}
|
||||||
>
|
>
|
||||||
<EditPost
|
<EditPost
|
||||||
notebooks={state.notebooks}
|
notebooks={notebooks}
|
||||||
book={notebook}
|
book={notebook}
|
||||||
note={note}
|
note={note}
|
||||||
ship={ship}
|
ship={ship}
|
||||||
@ -288,7 +290,7 @@ export default class PublishApp extends React.Component {
|
|||||||
rightPanelHide={false}
|
rightPanelHide={false}
|
||||||
sidebarShown={state.sidebarShown}
|
sidebarShown={state.sidebarShown}
|
||||||
invites={state.invites}
|
invites={state.invites}
|
||||||
notebooks={state.notebooks}
|
notebooks={notebooks}
|
||||||
associations={associations}
|
associations={associations}
|
||||||
selectedGroups={selectedGroups}
|
selectedGroups={selectedGroups}
|
||||||
contacts={contacts}
|
contacts={contacts}
|
||||||
@ -296,7 +298,7 @@ export default class PublishApp extends React.Component {
|
|||||||
api={this.api}
|
api={this.api}
|
||||||
>
|
>
|
||||||
<Note
|
<Note
|
||||||
notebooks={state.notebooks}
|
notebooks={notebooks}
|
||||||
book={notebook}
|
book={notebook}
|
||||||
groups={state.groups}
|
groups={state.groups}
|
||||||
contacts={notebookContacts}
|
contacts={notebookContacts}
|
||||||
|
@ -8,7 +8,7 @@ const CommentInput = React.forwardRef((props, ref) => (
|
|||||||
name="comment"
|
name="comment"
|
||||||
placeholder="Leave a comment here"
|
placeholder="Leave a comment here"
|
||||||
className={
|
className={
|
||||||
'f9 db border-box w-100 ba b--gray3 pt3 ph3 br1 ' +
|
'f9 db border-box w-100 ba b--gray3 pt2 ph2 br1 ' +
|
||||||
'b--gray2-d mb2 focus-b--black focus-b--white-d white-d bg-gray0-d'
|
'b--gray2-d mb2 focus-b--black focus-b--white-d white-d bg-gray0-d'
|
||||||
}
|
}
|
||||||
aria-describedby="comment-desc"
|
aria-describedby="comment-desc"
|
||||||
|
@ -53,7 +53,7 @@ export class Comments extends Component {
|
|||||||
|
|
||||||
this.textArea.value = '';
|
this.textArea.value = '';
|
||||||
this.setState({ commentBody: '', awaiting: 'new' });
|
this.setState({ commentBody: '', awaiting: 'new' });
|
||||||
const submit = this.props.api.action('publish', 'publish-action', comment);
|
const submit = this.props.api.publishAction(comment);
|
||||||
submit.then(() => {
|
submit.then(() => {
|
||||||
this.setState({ awaiting: null });
|
this.setState({ awaiting: null });
|
||||||
});
|
});
|
||||||
@ -88,7 +88,7 @@ export class Comments extends Component {
|
|||||||
this.setState({ awaiting: 'edit' });
|
this.setState({ awaiting: 'edit' });
|
||||||
|
|
||||||
window.api
|
window.api
|
||||||
.action('publish', 'publish-action', comment)
|
.publishAction(comment)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.setState({ awaiting: null, editing: null });
|
this.setState({ awaiting: null, editing: null });
|
||||||
});
|
});
|
||||||
@ -107,7 +107,7 @@ export class Comments extends Component {
|
|||||||
|
|
||||||
this.setState({ awaiting: { kind: 'del', what: idx } });
|
this.setState({ awaiting: { kind: 'del', what: idx } });
|
||||||
window.api
|
window.api
|
||||||
.action('publish', 'publish-action', comment)
|
.publishAction(comment)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.setState({ awaiting: null });
|
this.setState({ awaiting: null });
|
||||||
});
|
});
|
||||||
|
@ -20,18 +20,21 @@ export class EditPost extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { props } = this;
|
this.componentDidUpdate();
|
||||||
if (!(props.notebooks[props.ship]) ||
|
}
|
||||||
!(props.notebooks[props.ship][props.book]) ||
|
|
||||||
!(props.notebooks[props.ship][props.book].notes[props.note]) ||
|
componentDidUpdate(prevProps) {
|
||||||
!(props.notebooks[props.ship][props.book].notes[props.note].file)) {
|
const { props, state } = this;
|
||||||
this.props.api.fetchNote(props.ship, props.book, props.note);
|
if (prevProps && prevProps.api !== props.api) {
|
||||||
} else {
|
if (!(props.notebooks[props.ship]?.[props.book]?.notes?.[props.note]?.file)) {
|
||||||
const notebook = props.notebooks[props.ship][props.book];
|
props.api?.fetchNote(props.ship, props.book, props.note);
|
||||||
const note = notebook.notes[props.note];
|
} else if (state.body === '') {
|
||||||
const file = note.file;
|
const notebook = props.notebooks[props.ship][props.book];
|
||||||
const body = file.slice(file.indexOf(';>') + 3);
|
const note = notebook.notes[props.note];
|
||||||
this.setState({ body: body });
|
const file = note.file;
|
||||||
|
const body = file.slice(file.indexOf(';>') + 3);
|
||||||
|
this.setState({ body: body });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +53,7 @@ export class EditPost extends Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.setState({ awaiting: true });
|
this.setState({ awaiting: true });
|
||||||
this.props.api.action('publish', 'publish-action', editNote).then(() => {
|
this.props.api.publishAction(editNote).then(() => {
|
||||||
const editIndex = props.location.pathname.indexOf('/edit');
|
const editIndex = props.location.pathname.indexOf('/edit');
|
||||||
const noteHref = props.location.pathname.slice(0, editIndex);
|
const noteHref = props.location.pathname.slice(0, editIndex);
|
||||||
this.setState({ awaiting: false });
|
this.setState({ awaiting: false });
|
||||||
@ -112,7 +115,7 @@ export class EditPost extends Component {
|
|||||||
to={popoutHref}
|
to={popoutHref}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<img src="/~publish/popout.png"
|
<img src="/~landscape/img/popout.png"
|
||||||
height={16}
|
height={16}
|
||||||
width={16}
|
width={16}
|
||||||
/>
|
/>
|
||||||
|
@ -93,7 +93,7 @@ export class JoinScreen extends Component {
|
|||||||
|
|
||||||
// TODO: askHistory setting
|
// TODO: askHistory setting
|
||||||
this.setState({ disable: true });
|
this.setState({ disable: true });
|
||||||
this.props.api.action('publish','publish-action', actionData).catch((err) => {
|
this.props.api.publishAction(actionData).catch((err) => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.setState({ awaiting: text });
|
this.setState({ awaiting: text });
|
||||||
|
@ -37,14 +37,14 @@ export class NewPost extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.setState({ disabled: true });
|
this.setState({ disabled: true });
|
||||||
this.props.api.action('publish', 'publish-action', newNote).then(() => {
|
this.props.api.publishAction(newNote).then(() => {
|
||||||
this.setState({ awaiting: newNote['new-note'].note });
|
this.setState({ awaiting: newNote['new-note'].note });
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
if (err.includes('note already exists')) {
|
if (err.includes('note already exists')) {
|
||||||
const timestamp = Math.floor(Date.now() / 1000);
|
const timestamp = Math.floor(Date.now() / 1000);
|
||||||
newNote['new-note'].note += '-' + timestamp;
|
newNote['new-note'].note += '-' + timestamp;
|
||||||
this.setState({ awaiting: newNote['new-note'].note });
|
this.setState({ awaiting: newNote['new-note'].note });
|
||||||
this.props.api.action('publish', 'publish-action', newNote);
|
this.props.api.publishAction(newNote);
|
||||||
} else {
|
} else {
|
||||||
this.setState({ disabled: false, awaiting: null });
|
this.setState({ disabled: false, awaiting: null });
|
||||||
}
|
}
|
||||||
@ -52,11 +52,15 @@ export class NewPost extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
this.props.api.fetchNotebook(this.props.ship, this.props.book);
|
this.componentDidUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate(prevProps) {
|
||||||
|
if (prevProps && prevProps.api !== this.props.api) {
|
||||||
|
this.props.api.fetchNotebook(this.props.ship, this.props.book);
|
||||||
|
}
|
||||||
|
|
||||||
const notebook = this.props.notebooks[this.props.ship][this.props.book];
|
const notebook = this.props.notebooks[this.props.ship][this.props.book];
|
||||||
if (notebook.notes[this.state.awaiting]) {
|
if (notebook.notes[this.state.awaiting]) {
|
||||||
this.setState({ disabled: false, awaiting: null });
|
this.setState({ disabled: false, awaiting: null });
|
||||||
@ -131,7 +135,7 @@ export class NewPost extends Component {
|
|||||||
to={popoutHref}
|
to={popoutHref}
|
||||||
target='_blank'
|
target='_blank'
|
||||||
>
|
>
|
||||||
<img src='/~publish/popout.png' height={16} width={16} />
|
<img src='/~landscape/img/popout.png' height={16} width={16} />
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className='mw6 center'>
|
<div className='mw6 center'>
|
||||||
|
@ -93,7 +93,7 @@ export class NewScreen extends Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.setState({ awaiting: bookId, disabled: true }, () => {
|
this.setState({ awaiting: bookId, disabled: true }, () => {
|
||||||
props.api.action('publish', 'publish-action', action).then(() => {
|
props.api.publishAction(action).then(() => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -40,54 +40,40 @@ export class Note extends Component {
|
|||||||
this.deletePost = this.deletePost.bind(this);
|
this.deletePost = this.deletePost.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
const readAction = {
|
|
||||||
read: {
|
|
||||||
who: this.props.ship.slice(1),
|
|
||||||
book: this.props.book,
|
|
||||||
note: this.props.note
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.props.api.action('publish', 'publish-action', readAction);
|
|
||||||
this.props.api.fetchNote(this.props.ship, this.props.book, this.props.note);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (!(this.props.notebooks[this.props.ship]) ||
|
this.componentDidUpdate();
|
||||||
!(this.props.notebooks[this.props.ship][this.props.book]) ||
|
|
||||||
!(this.props.notebooks[this.props.ship][this.props.book].notes[this.props.note]) ||
|
|
||||||
!(this.props.notebooks[this.props.ship][this.props.book].notes[this.props.note].file)) {
|
|
||||||
this.props.api.fetchNote(this.props.ship, this.props.book, this.props.note);
|
|
||||||
}
|
|
||||||
this.onScroll();
|
this.onScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if (!(this.props.notebooks[this.props.ship]) ||
|
const { props } = this;
|
||||||
!(this.props.notebooks[this.props.ship][this.props.book]) ||
|
if ((prevProps && prevProps.api !== props.api) || props.api) {
|
||||||
!(this.props.notebooks[this.props.ship][this.props.book].notes[this.props.note]) ||
|
if (!(props.notebooks[props.ship]?.[props.book]?.notes?.[props.note]?.file)) {
|
||||||
!(this.props.notebooks[this.props.ship][this.props.book].notes[this.props.note].file)) {
|
props.api.fetchNote(props.ship, props.book, props.note);
|
||||||
this.props.api.fetchNote(this.props.ship, this.props.book, this.props.note);
|
}
|
||||||
}
|
|
||||||
if ((prevProps.book !== this.props.book) ||
|
if (prevProps) {
|
||||||
(prevProps.note !== this.props.note) ||
|
if ((prevProps.book !== props.book) ||
|
||||||
(prevProps.ship !== this.props.ship)) {
|
(prevProps.note !== props.note) ||
|
||||||
const readAction = {
|
(prevProps.ship !== props.ship)) {
|
||||||
read: {
|
const readAction = {
|
||||||
who: this.props.ship.slice(1),
|
read: {
|
||||||
book: this.props.book,
|
who: props.ship.slice(1),
|
||||||
note: this.props.note
|
book: props.book,
|
||||||
|
note: props.note
|
||||||
|
}
|
||||||
|
};
|
||||||
|
props.api.publishAction(readAction);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
this.props.api.action('publish', 'publish-action', readAction);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onScroll() {
|
onScroll() {
|
||||||
const notebook = this.props.notebooks[this.props.ship][this.props.book];
|
const notebook = this.props.notebooks?.[this.props.ship]?.[this.props.book];
|
||||||
const note = notebook.notes[this.props.note];
|
const note = notebook?.notes?.[this.props.note];
|
||||||
|
|
||||||
if (!note.comments) {
|
if (!note?.comments) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +109,7 @@ export class Note extends Component {
|
|||||||
const popout = (props.popout) ? 'popout/' : '';
|
const popout = (props.popout) ? 'popout/' : '';
|
||||||
const baseUrl = `/~publish/${popout}notebook/${props.ship}/${props.book}`;
|
const baseUrl = `/~publish/${popout}notebook/${props.ship}/${props.book}`;
|
||||||
this.setState({ deleting: true });
|
this.setState({ deleting: true });
|
||||||
this.props.api.action('publish', 'publish-action', deleteAction)
|
this.props.api.publishAction(deleteAction)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
props.history.push(baseUrl);
|
props.history.push(baseUrl);
|
||||||
});
|
});
|
||||||
@ -131,12 +117,12 @@ export class Note extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { props } = this;
|
const { props } = this;
|
||||||
const notebook = props.notebooks[props.ship][props.book] || {};
|
const notebook = props.notebooks?.[props.ship]?.[props.book] || {};
|
||||||
const comments = notebook.notes[props.note].comments || false;
|
const comments = notebook?.notes?.[props.note]?.comments || false;
|
||||||
const title = notebook.notes[props.note].title || '';
|
const title = notebook?.notes?.[props.note]?.title || '';
|
||||||
const author = notebook.notes[props.note].author || '';
|
const author = notebook?.notes?.[props.note]?.author || '';
|
||||||
const file = notebook.notes[props.note].file || '';
|
const file = notebook?.notes?.[props.note]?.file || '';
|
||||||
const date = moment(notebook.notes[props.note]['date-created']).fromNow() || 0;
|
const date = moment(notebook.notes?.[props.note]?.['date-created']).fromNow() || 0;
|
||||||
|
|
||||||
const contact = author.substr(1) in props.contacts
|
const contact = author.substr(1) in props.contacts
|
||||||
? props.contacts[author.substr(1)] : false;
|
? props.contacts[author.substr(1)] : false;
|
||||||
@ -156,22 +142,24 @@ export class Note extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newfile = file.slice(file.indexOf(';>')+2);
|
const newfile = file.slice(file.indexOf(';>')+2);
|
||||||
const prevId = notebook.notes[props.note]['prev-note'] || null;
|
const prevId = notebook?.notes?.[props.note]?.['prev-note'] || null;
|
||||||
const nextId = notebook.notes[props.note]['next-note'] || null;
|
const nextId = notebook?.notes?.[props.note]?.['next-note'] || null;
|
||||||
|
const prevDate = moment(notebook?.notes?.[prevId]?.['date-created']).fromNow() || 0;
|
||||||
|
const nextDate = moment(notebook?.notes?.[nextId]?.['date-created']).fromNow() || 0;
|
||||||
|
|
||||||
const prev = (prevId === null)
|
const prev = (prevId === null)
|
||||||
? null
|
? null
|
||||||
: {
|
: {
|
||||||
id: prevId,
|
id: prevId,
|
||||||
title: notebook.notes[prevId].title,
|
title: notebook?.notes?.[prevId]?.title,
|
||||||
date: moment(notebook.notes[prevId]['date-created']).fromNow()
|
date: prevDate
|
||||||
};
|
};
|
||||||
const next = (nextId === null)
|
const next = (nextId === null)
|
||||||
? null
|
? null
|
||||||
: {
|
: {
|
||||||
id: nextId,
|
id: nextId,
|
||||||
title: notebook.notes[nextId].title,
|
title: notebook?.notes?.[nextId]?.title,
|
||||||
date: moment(notebook.notes[nextId]['date-created']).fromNow()
|
date: nextDate
|
||||||
};
|
};
|
||||||
|
|
||||||
let editPost = null;
|
let editPost = null;
|
||||||
@ -218,7 +206,7 @@ export class Note extends Component {
|
|||||||
className={'dn absolute right-1 top-1 ' + hiddenOnPopout}
|
className={'dn absolute right-1 top-1 ' + hiddenOnPopout}
|
||||||
target='_blank'
|
target='_blank'
|
||||||
>
|
>
|
||||||
<img src='/~publish/popout.png' height={16} width={16} />
|
<img src='/~landscape/img/popout.png' height={16} width={16} />
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className='w-100 mw6'>
|
<div className='w-100 mw6'>
|
||||||
|
@ -24,13 +24,13 @@ export class Notebook extends Component {
|
|||||||
if (scrollHeight - scrollTop - clientHeight < 40) {
|
if (scrollHeight - scrollTop - clientHeight < 40) {
|
||||||
atBottom = true;
|
atBottom = true;
|
||||||
}
|
}
|
||||||
if (!notebook.notes) {
|
if (!notebook.notes && this.props.api) {
|
||||||
this.props.api.fetchNotebook(this.props.ship, this.props.book);
|
this.props.api.fetchNotebook(this.props.ship, this.props.book);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadedNotes = Object.keys(notebook.notes).length;
|
const loadedNotes = Object.keys(notebook?.notes).length || 0;
|
||||||
const allNotes = notebook['notes-by-date'].length;
|
const allNotes = notebook?.['notes-by-date'].length || 0;
|
||||||
|
|
||||||
const fullyLoaded = (loadedNotes === allNotes);
|
const fullyLoaded = (loadedNotes === allNotes);
|
||||||
|
|
||||||
@ -39,20 +39,20 @@ export class Notebook extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
this.props.api.fetchNotebook(this.props.ship, this.props.book);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
const notebook = this.props.notebooks[this.props.ship][this.props.book];
|
const { props } = this;
|
||||||
if (!notebook.subscribers) {
|
if ((prevProps && (prevProps.api !== props.api)) || props.api) {
|
||||||
this.props.api.fetchNotebook(this.props.ship, this.props.book);
|
const notebook = props.notebooks?.[props.ship]?.[props.book];
|
||||||
|
if (!notebook?.subscribers) {
|
||||||
|
props.api.fetchNotebook(props.ship, props.book);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const notebook = this.props.notebooks[this.props.ship][this.props.book];
|
this.componentDidUpdate();
|
||||||
if (notebook.notes) {
|
const notebook = this.props.notebooks?.[this.props.ship]?.[this.props.book];
|
||||||
|
if (notebook?.notes) {
|
||||||
this.onScroll();
|
this.onScroll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,7 +64,7 @@ export class Notebook extends Component {
|
|||||||
book: this.props.book
|
book: this.props.book
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.props.api.action('publish', 'publish-action', action);
|
this.props.api.publishAction(action);
|
||||||
this.props.history.push('/~publish');
|
this.props.history.push('/~publish');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ export class Notebook extends Component {
|
|||||||
|
|
||||||
const hiddenOnPopout = props.popout ? '' : 'dib-m dib-l dib-xl';
|
const hiddenOnPopout = props.popout ? '' : 'dib-m dib-l dib-xl';
|
||||||
|
|
||||||
const notebook = props.notebooks[props.ship][props.book];
|
const notebook = props.notebooks?.[props.ship]?.[props.book];
|
||||||
|
|
||||||
const tabStyles = {
|
const tabStyles = {
|
||||||
posts: 'bb b--gray4 b--gray2-d gray2 pv4 ph2',
|
posts: 'bb b--gray4 b--gray2-d gray2 pv4 ph2',
|
||||||
@ -91,8 +91,8 @@ export class Notebook extends Component {
|
|||||||
let inner = null;
|
let inner = null;
|
||||||
switch (props.view) {
|
switch (props.view) {
|
||||||
case 'posts': {
|
case 'posts': {
|
||||||
const notesList = notebook['notes-by-date'] || [];
|
const notesList = notebook?.['notes-by-date'] || [];
|
||||||
const notes = notebook.notes || null;
|
const notes = notebook?.notes || null;
|
||||||
inner = <NotebookPosts notes={notes}
|
inner = <NotebookPosts notes={notes}
|
||||||
popout={props.popout}
|
popout={props.popout}
|
||||||
list={notesList}
|
list={notesList}
|
||||||
@ -103,7 +103,7 @@ export class Notebook extends Component {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'about':
|
case 'about':
|
||||||
inner = <p className="f8 lh-solid">{notebook.about}</p>;
|
inner = <p className="f8 lh-solid">{notebook?.about}</p>;
|
||||||
break;
|
break;
|
||||||
case 'subscribers':
|
case 'subscribers':
|
||||||
inner = <Subscribers
|
inner = <Subscribers
|
||||||
@ -112,6 +112,7 @@ export class Notebook extends Component {
|
|||||||
notebook={notebook}
|
notebook={notebook}
|
||||||
permissions={this.props.permissions}
|
permissions={this.props.permissions}
|
||||||
groups={this.props.groups}
|
groups={this.props.groups}
|
||||||
|
api={this.props.api}
|
||||||
/>;
|
/>;
|
||||||
break;
|
break;
|
||||||
case 'settings':
|
case 'settings':
|
||||||
@ -123,6 +124,7 @@ export class Notebook extends Component {
|
|||||||
contacts={this.props.contacts}
|
contacts={this.props.contacts}
|
||||||
associations={this.props.associations}
|
associations={this.props.associations}
|
||||||
history={this.props.history}
|
history={this.props.history}
|
||||||
|
api={this.props.api}
|
||||||
/>;
|
/>;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -150,9 +152,9 @@ export class Notebook extends Component {
|
|||||||
const newUrl = base + '/new';
|
const newUrl = base + '/new';
|
||||||
|
|
||||||
let newPost = null;
|
let newPost = null;
|
||||||
if (notebook['writers-group-path'] in props.groups) {
|
if (notebook?.['writers-group-path'] in props.groups) {
|
||||||
const writers = notebook['writers-group-path'];
|
const writers = notebook?.['writers-group-path'];
|
||||||
if (props.groups[writers].has(window.ship)) {
|
if (props.groups?.[writers].has(window.ship)) {
|
||||||
newPost = (
|
newPost = (
|
||||||
<Link
|
<Link
|
||||||
to={newUrl}
|
to={newUrl}
|
||||||
@ -186,7 +188,7 @@ export class Notebook extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className='overflow-y-scroll'
|
className='overflow-y-scroll h-100'
|
||||||
style={{ paddingLeft: 16, paddingRight: 16 }}
|
style={{ paddingLeft: 16, paddingRight: 16 }}
|
||||||
onScroll={this.onScroll}
|
onScroll={this.onScroll}
|
||||||
ref={(el) => {
|
ref={(el) => {
|
||||||
@ -213,12 +215,12 @@ export class Notebook extends Component {
|
|||||||
to={popoutHref}
|
to={popoutHref}
|
||||||
target='_blank'
|
target='_blank'
|
||||||
>
|
>
|
||||||
<img src='/~publish/popout.png' height={16} width={16} />
|
<img src='/~landscape/img/popout.png' height={16} width={16} />
|
||||||
</Link>
|
</Link>
|
||||||
<div className='h-100 pt0 pt8-m pt8-l pt8-xl no-scrollbar'>
|
<div className='h-100 pt0 pt8-m pt8-l pt8-xl no-scrollbar'>
|
||||||
<div className='flex justify-between' style={{ marginBottom: 32 }}>
|
<div className='flex justify-between' style={{ marginBottom: 32 }}>
|
||||||
<div className='flex-col'>
|
<div className='flex-col'>
|
||||||
<div className='mb1'>{notebook.title}</div>
|
<div className='mb1'>{notebook?.title}</div>
|
||||||
<span>
|
<span>
|
||||||
<span className='gray3 mr1'>by</span>
|
<span className='gray3 mr1'>by</span>
|
||||||
<span
|
<span
|
||||||
|
@ -63,7 +63,7 @@ export class Settings extends Component {
|
|||||||
|
|
||||||
changeComments() {
|
changeComments() {
|
||||||
this.setState({ comments: !this.state.comments, disabled: true }, (() => {
|
this.setState({ comments: !this.state.comments, disabled: true }, (() => {
|
||||||
this.props.api.action('publish', 'publish-action', {
|
this.props.api.publishAction({
|
||||||
'edit-book': {
|
'edit-book': {
|
||||||
book: this.props.book,
|
book: this.props.book,
|
||||||
title: this.props.notebook.title,
|
title: this.props.notebook.title,
|
||||||
@ -84,7 +84,7 @@ export class Settings extends Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.setState({ disabled: true, type: 'Deleting' });
|
this.setState({ disabled: true, type: 'Deleting' });
|
||||||
this.props.api.action('publish', 'publish-action', action).then(() => {
|
this.props.api.publishAction(action).then(() => {
|
||||||
this.props.history.push('/~publish');
|
this.props.history.push('/~publish');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -108,7 +108,7 @@ export class Settings extends Component {
|
|||||||
disabled: true,
|
disabled: true,
|
||||||
type: 'Converting'
|
type: 'Converting'
|
||||||
}, (() => {
|
}, (() => {
|
||||||
this.props.api.action('publish', 'publish-action', {
|
this.props.api.publishAction({
|
||||||
groupify: {
|
groupify: {
|
||||||
book: props.book,
|
book: props.book,
|
||||||
target: state.targetGroup,
|
target: state.targetGroup,
|
||||||
@ -125,7 +125,7 @@ export class Settings extends Component {
|
|||||||
|
|
||||||
const ownedUnmanaged =
|
const ownedUnmanaged =
|
||||||
owner &&
|
owner &&
|
||||||
props.notebook['writers-group-path'].slice(0, 3) === '/~/';
|
props.notebook?.['writers-group-path'].slice(0, 3) === '/~/';
|
||||||
|
|
||||||
if (!ownedUnmanaged) {
|
if (!ownedUnmanaged) {
|
||||||
return null;
|
return null;
|
||||||
@ -162,11 +162,9 @@ export class Settings extends Component {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className={'w-100 fl mt3 mb3'} style={{ maxWidth: '29rem' }}>
|
<div className={'w-100 fl mt3 mb3'} style={{ maxWidth: '29rem' }}>
|
||||||
<p className="f8 mt3 lh-copy db">Convert Notebook</p>
|
{this.renderHeader(
|
||||||
<p className="f9 gray2 db mb4">
|
'Convert Notebook',
|
||||||
Convert this notebook into a group with associated chat, or select a
|
'Convert this notebook into a group with associated chat, or select a group to add this notebook to.')}
|
||||||
group to add this notebook to.
|
|
||||||
</p>
|
|
||||||
<InviteSearch
|
<InviteSearch
|
||||||
groups={props.groups}
|
groups={props.groups}
|
||||||
contacts={props.contacts}
|
contacts={props.contacts}
|
||||||
@ -185,7 +183,7 @@ export class Settings extends Component {
|
|||||||
className={'dib f9 black gray4-d bg-gray0-d ba pa2 mt4 b--black b--gray1-d pointer'}
|
className={'dib f9 black gray4-d bg-gray0-d ba pa2 mt4 b--black b--gray1-d pointer'}
|
||||||
disabled={this.state.disabled}
|
disabled={this.state.disabled}
|
||||||
>
|
>
|
||||||
Convert to group
|
{state.targetGroup ? 'Add to group' : 'Convert to group'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -193,14 +191,22 @@ export class Settings extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderHeader(title, subtitle) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p className="f9 mt6 lh-copy">{title}</p>
|
||||||
|
<p className="f9 gray2 db mb4">{subtitle}</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const commentsSwitchClasses = (this.state.comments)
|
const commentsSwitchClasses = (this.state.comments)
|
||||||
? 'relative checked bg-green2 br3 h1 toggle v-mid z-0'
|
? 'relative checked bg-green2 br3 h1 toggle v-mid z-0'
|
||||||
: 'relative bg-gray4 bg-gray1-d br3 h1 toggle v-mid z-0';
|
: 'relative bg-gray4 bg-gray1-d br3 h1 toggle v-mid z-0';
|
||||||
|
|
||||||
const copyShortcode = <div>
|
const copyShortcode = <div>
|
||||||
<p className="f9 mt3 lh-copy">Share</p>
|
{this.renderHeader('Share', 'Share a shortcode to join this notebook')}
|
||||||
<p className="f9 gray2 mb4">Share a shortcode to join this notebook</p>
|
|
||||||
<div className="relative w-100 flex" style={{ maxWidth: '29rem' }}>
|
<div className="relative w-100 flex" style={{ maxWidth: '29rem' }}>
|
||||||
<input
|
<input
|
||||||
className={'f8 mono ba b--gray3 b--gray2-d bg-gray0-d white-d ' +
|
className={'f8 mono ba b--gray3 b--gray2-d bg-gray0-d white-d ' +
|
||||||
@ -226,19 +232,16 @@ export class Settings extends Component {
|
|||||||
<div className="flex-column">
|
<div className="flex-column">
|
||||||
{copyShortcode}
|
{copyShortcode}
|
||||||
{this.renderGroupify()}
|
{this.renderGroupify()}
|
||||||
<p className="f9 mt6 lh-copy db">Delete Notebook</p>
|
{this.renderHeader(
|
||||||
<p className="f9 gray2 db mb4">
|
'Delete Notebook',
|
||||||
Permanently delete this notebook. (All current members will no
|
'Permanently delete this notebook. (All current members will no longer see this notebook)')}
|
||||||
longer see this notebook)
|
|
||||||
</p>
|
|
||||||
<button
|
<button
|
||||||
className="bg-transparent b--red2 red2 pointer dib f9 ba pa2"
|
className="bg-transparent b--red2 red2 pointer dib f9 ba pa2"
|
||||||
onClick={this.deleteNotebook}
|
onClick={this.deleteNotebook}
|
||||||
>
|
>
|
||||||
Delete this notebook
|
Delete this notebook
|
||||||
</button>
|
</button>
|
||||||
<p className="f9 mt6 lh-copy">Rename</p>
|
{this.renderHeader('Rename', 'Change the name of this notebook')}
|
||||||
<p className="f9 gray2 db mb4">Change the name of this notebook</p>
|
|
||||||
<div className="relative w-100 flex" style={{ maxWidth: '29rem' }}>
|
<div className="relative w-100 flex" style={{ maxWidth: '29rem' }}>
|
||||||
<input
|
<input
|
||||||
className={
|
className={
|
||||||
@ -251,7 +254,7 @@ export class Settings extends Component {
|
|||||||
onBlur={() => {
|
onBlur={() => {
|
||||||
this.setState({ disabled: true });
|
this.setState({ disabled: true });
|
||||||
this.props.api
|
this.props.api
|
||||||
.action('publish', 'publish-action', {
|
.publishAction({
|
||||||
'edit-book': {
|
'edit-book': {
|
||||||
book: this.props.book,
|
book: this.props.book,
|
||||||
title: this.state.title,
|
title: this.state.title,
|
||||||
@ -266,8 +269,7 @@ export class Settings extends Component {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p className="f9 mt6 lh-copy">Change description</p>
|
{this.renderHeader("Change description", "Change the description of this notebook")}
|
||||||
<p className="f9 gray2 db mb4">Change the description of this notebook</p>
|
|
||||||
<div className="relative w-100 flex" style={{ maxWidth: '29rem' }}>
|
<div className="relative w-100 flex" style={{ maxWidth: '29rem' }}>
|
||||||
<input
|
<input
|
||||||
className={
|
className={
|
||||||
@ -279,7 +281,7 @@ export class Settings extends Component {
|
|||||||
onBlur={() => {
|
onBlur={() => {
|
||||||
this.setState({ disabled: true });
|
this.setState({ disabled: true });
|
||||||
this.props.api
|
this.props.api
|
||||||
.action('publish', 'publish-action', {
|
.publishAction({
|
||||||
'edit-book': {
|
'edit-book': {
|
||||||
book: this.props.book,
|
book: this.props.book,
|
||||||
title: this.props.notebook.title,
|
title: this.props.notebook.title,
|
||||||
|
@ -8,7 +8,7 @@ export class SidebarInvite extends Component {
|
|||||||
uid: this.props.uid
|
uid: this.props.uid
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
window.api.action('invite-store', 'invite-action', action);
|
this.props.api.inviteAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
onDecline() {
|
onDecline() {
|
||||||
@ -18,7 +18,7 @@ export class SidebarInvite extends Component {
|
|||||||
uid: this.props.uid
|
uid: this.props.uid
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.props.api.action('invite-store', 'invite-action', action);
|
this.props.api.inviteAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -17,7 +17,7 @@ export class Subscribers extends Component {
|
|||||||
path: path
|
path: path
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.props.api.action('group-store', 'group-action', action);
|
this.props.api.groupAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeUser(who, path) {
|
removeUser(who, path) {
|
||||||
@ -27,7 +27,7 @@ export class Subscribers extends Component {
|
|||||||
path: path
|
path: path
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.props.api.action('group-store', 'group-action', action);
|
this.props.api.groupAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
redirect(url) {
|
redirect(url) {
|
||||||
|
15
pkg/interface/src/components/404.js
Normal file
15
pkg/interface/src/components/404.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const NotFound = () => <div
|
||||||
|
className="fixed inter tc"
|
||||||
|
style={{
|
||||||
|
top: '50vh',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -25vh)',
|
||||||
|
fontFeatureSettings: '\'zero\' 1' }}>
|
||||||
|
<h1 className="fw2 f2">404</h1>
|
||||||
|
<p className="tc">Not found.<br /><br />
|
||||||
|
If this is unexpected, email <code>support@tlon.io</code> or <a className="bb" href="https://github.com/urbit/urbit/issues/new/choose">submit an issue</a>.</p>
|
||||||
|
</div>;
|
||||||
|
|
||||||
|
export default NotFound;
|
@ -10,7 +10,7 @@ export class Spinner extends Component {
|
|||||||
return (
|
return (
|
||||||
<div className={classes + ' z-2 bg-white bg-gray0-d white-d'}>
|
<div className={classes + ' z-2 bg-white bg-gray0-d white-d'}>
|
||||||
<img className="invert-d spin-active v-mid"
|
<img className="invert-d spin-active v-mid"
|
||||||
src="/~chat/img/Spinner.png"
|
src="/~landscape/img/Spinner.png"
|
||||||
width={16}
|
width={16}
|
||||||
height={16}
|
height={16}
|
||||||
/>
|
/>
|
||||||
|
@ -7,14 +7,16 @@ import { Sigil } from '../lib/sigil';
|
|||||||
const getLocationName = (basePath) => {
|
const getLocationName = (basePath) => {
|
||||||
if (basePath === '~chat')
|
if (basePath === '~chat')
|
||||||
return 'Chat';
|
return 'Chat';
|
||||||
if (basePath === '~dojo')
|
else if (basePath === '~dojo')
|
||||||
return 'Dojo';
|
return 'Dojo';
|
||||||
if (basePath === '~groups')
|
else if (basePath === '~groups')
|
||||||
return 'Groups';
|
return 'Groups';
|
||||||
if (basePath === '~link')
|
else if (basePath === '~link')
|
||||||
return 'Links';
|
return 'Links';
|
||||||
if (basePath === '~publish')
|
else if (basePath === '~publish')
|
||||||
return 'Publish';
|
return 'Publish';
|
||||||
|
else
|
||||||
|
return 'Unknown';
|
||||||
};
|
};
|
||||||
|
|
||||||
const StatusBar = (props) => {
|
const StatusBar = (props) => {
|
||||||
@ -24,8 +26,9 @@ const StatusBar = (props) => {
|
|||||||
? 'Home'
|
? 'Home'
|
||||||
: getLocationName(basePath);
|
: getLocationName(basePath);
|
||||||
|
|
||||||
const popout = window.location.href.includes('popout/')
|
const display = (!window.location.href.includes('popout/') &&
|
||||||
? 'dn' : 'db';
|
(locationName !== 'Unknown'))
|
||||||
|
? 'db' : 'dn';
|
||||||
|
|
||||||
const invites = (props.invites && props.invites['/contacts'])
|
const invites = (props.invites && props.invites['/contacts'])
|
||||||
? props.invites['/contacts']
|
? props.invites['/contacts']
|
||||||
@ -34,7 +37,7 @@ const StatusBar = (props) => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'bg-white bg-gray0-d w-100 justify-between relative tc pt3 ' + popout
|
'bg-white bg-gray0-d w-100 justify-between relative tc pt3 ' + display
|
||||||
}
|
}
|
||||||
style={{ height: 45 }}
|
style={{ height: 45 }}
|
||||||
>
|
>
|
||||||
@ -54,7 +57,7 @@ const StatusBar = (props) => {
|
|||||||
location.pathname === '/'
|
location.pathname === '/'
|
||||||
? null
|
? null
|
||||||
: <Link
|
: <Link
|
||||||
className="dib f9 v-mid inter ml2 no-underline"
|
className="dib f9 v-mid inter ml2 no-underline white-d"
|
||||||
to="/"
|
to="/"
|
||||||
style={{ top: 14 }}
|
style={{ top: 14 }}
|
||||||
>
|
>
|
||||||
|
@ -4,6 +4,7 @@ export default class InviteReducer {
|
|||||||
reduce(json, state) {
|
reduce(json, state) {
|
||||||
const data = _.get(json, 'invite-update', false);
|
const data = _.get(json, 'invite-update', false);
|
||||||
if (data) {
|
if (data) {
|
||||||
|
console.log(data);
|
||||||
this.initial(data, state);
|
this.initial(data, state);
|
||||||
this.create(data, state);
|
this.create(data, state);
|
||||||
this.delete(data, state);
|
this.delete(data, state);
|
||||||
|
@ -4,25 +4,32 @@ export default class MetadataReducer {
|
|||||||
reduce(json, state) {
|
reduce(json, state) {
|
||||||
let data = _.get(json, 'metadata-update', false);
|
let data = _.get(json, 'metadata-update', false);
|
||||||
if (data) {
|
if (data) {
|
||||||
|
console.log('data: ', data);
|
||||||
this.associations(data, state);
|
this.associations(data, state);
|
||||||
this.add(data, state);
|
this.add(data, state);
|
||||||
this.update(data, state);
|
this.update(data, state);
|
||||||
this.remove(data, state);
|
this.remove(data, state);
|
||||||
|
console.log('state: ', state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
associations(json, state) {
|
associations(json, state) {
|
||||||
let data = _.get(json, 'associations', false);
|
let data = _.get(json, 'associations', false);
|
||||||
if (data) {
|
if (data) {
|
||||||
let metadata = {};
|
let metadata = state.associations;
|
||||||
Object.keys(data).forEach((key) => {
|
Object.keys(data).forEach((key) => {
|
||||||
let val = data[key];
|
let val = data[key];
|
||||||
let groupPath = val['group-path'];
|
let appName = val['app-name'];
|
||||||
if (!(groupPath in metadata)) {
|
let appPath = val['app-path'];
|
||||||
metadata[groupPath] = {};
|
if (!(appName in metadata)) {
|
||||||
|
metadata[appName] = {};
|
||||||
}
|
}
|
||||||
metadata[groupPath][key] = val;
|
if (!(appPath in metadata[appName])) {
|
||||||
|
metadata[appName][appPath] = {};
|
||||||
|
}
|
||||||
|
metadata[appName][appPath] = val;
|
||||||
});
|
});
|
||||||
|
|
||||||
state.associations = metadata;
|
state.associations = metadata;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,11 +38,16 @@ export default class MetadataReducer {
|
|||||||
let data = _.get(json, 'add', false);
|
let data = _.get(json, 'add', false);
|
||||||
if (data) {
|
if (data) {
|
||||||
let metadata = state.associations;
|
let metadata = state.associations;
|
||||||
if (!(data['group-path'] in metadata)) {
|
let appName = data['app-name'];
|
||||||
metadata[data['group-path']] = {};
|
let appPath = data['app-path'];
|
||||||
|
|
||||||
|
if (!(appName in metadata)) {
|
||||||
|
metadata[appName] = {};
|
||||||
}
|
}
|
||||||
metadata[data['group-path']]
|
if (!(appPath in metadata[appName])) {
|
||||||
[`${data["group-path"]}/${data["app-name"]}${data["app-path"]}`] = data;
|
metadata[appName][appPath] = {};
|
||||||
|
}
|
||||||
|
metadata[appName][appPath] = data;
|
||||||
|
|
||||||
state.associations = metadata;
|
state.associations = metadata;
|
||||||
}
|
}
|
||||||
@ -45,12 +57,16 @@ export default class MetadataReducer {
|
|||||||
let data = _.get(json, 'update-metadata', false);
|
let data = _.get(json, 'update-metadata', false);
|
||||||
if (data) {
|
if (data) {
|
||||||
let metadata = state.associations;
|
let metadata = state.associations;
|
||||||
if (!(data["group-path"] in metadata)) {
|
let appName = data['app-name'];
|
||||||
metadata[data["group-path"]] = {};
|
let appPath = data['app-path'];
|
||||||
|
|
||||||
|
if (!(appName in metadata)) {
|
||||||
|
metadata[appName] = {};
|
||||||
}
|
}
|
||||||
metadata[data["group-path"]][
|
if (!(appPath in metadata[appName])) {
|
||||||
`${data["group-path"]}/${data["app-name"]}${data["app-path"]}`
|
metadata[appName][appPath] = {};
|
||||||
] = data;
|
}
|
||||||
|
metadata[appName][appPath] = data;
|
||||||
|
|
||||||
state.associations = metadata;
|
state.associations = metadata;
|
||||||
}
|
}
|
||||||
@ -60,12 +76,13 @@ export default class MetadataReducer {
|
|||||||
let data = _.get(json, 'remove', false);
|
let data = _.get(json, 'remove', false);
|
||||||
if (data) {
|
if (data) {
|
||||||
let metadata = state.associations;
|
let metadata = state.associations;
|
||||||
if (data['group-path'] in metadata) {
|
let appName = data['app-name'];
|
||||||
let path =
|
let appPath = data['app-path'];
|
||||||
`${data['group-path']}/${data['app-name']}${data['app-path']}`
|
|
||||||
delete metadata[data["group-path"]][path];
|
if (appName in metadata && appPath in metadata[appName]) {
|
||||||
state.associations = metadata;
|
delete metadata[appName][appPath];
|
||||||
}
|
}
|
||||||
|
state.associations = metadata;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,11 @@ export default class BaseStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleEvent(data) {
|
handleEvent(data) {
|
||||||
let json = data.data;
|
const json = data.data;
|
||||||
|
|
||||||
|
if (json === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ('clear' in json && json.clear) {
|
if ('clear' in json && json.clear) {
|
||||||
this.setState(this.initialState());
|
this.setState(this.initialState());
|
||||||
|
@ -12,7 +12,9 @@ export default class LaunchStore extends BaseStore {
|
|||||||
launch: {
|
launch: {
|
||||||
firstTime: false,
|
firstTime: false,
|
||||||
tileOrdering: [],
|
tileOrdering: [],
|
||||||
tiles: {}
|
tiles: {},
|
||||||
|
weather: {},
|
||||||
|
clock: {}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import BaseStore from './base';
|
import BaseStore from './base';
|
||||||
|
|
||||||
|
import ContactReducer from '../reducers/contact-update';
|
||||||
import GroupReducer from '../reducers/group-update';
|
import GroupReducer from '../reducers/group-update';
|
||||||
|
import LocalReducer from '../reducers/local';
|
||||||
import PublishReducer from '../reducers/publish-update';
|
import PublishReducer from '../reducers/publish-update';
|
||||||
import InviteReducer from '../reducers/invite-update';
|
import InviteReducer from '../reducers/invite-update';
|
||||||
import PublishResponseReducer from '../reducers/publish-response';
|
import PublishResponseReducer from '../reducers/publish-response';
|
||||||
@ -11,7 +13,9 @@ export default class PublishStore extends BaseStore {
|
|||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
this.contactReducer = new ContactReducer();
|
||||||
this.groupReducer = new GroupReducer();
|
this.groupReducer = new GroupReducer();
|
||||||
|
this.localReducer = new LocalReducer();
|
||||||
this.publishReducer = new PublishReducer();
|
this.publishReducer = new PublishReducer();
|
||||||
this.inviteReducer = new InviteReducer();
|
this.inviteReducer = new InviteReducer();
|
||||||
this.responseReducer = new PublishResponseReducer();
|
this.responseReducer = new PublishResponseReducer();
|
||||||
@ -34,7 +38,9 @@ export default class PublishStore extends BaseStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reduce(data, state) {
|
reduce(data, state) {
|
||||||
|
this.contactReducer.reduce(data, this.state);
|
||||||
this.groupReducer.reduce(data, this.state);
|
this.groupReducer.reduce(data, this.state);
|
||||||
|
this.localReducer.reduce(data, this.state);
|
||||||
this.publishReducer.reduce(data, this.state);
|
this.publishReducer.reduce(data, this.state);
|
||||||
this.permissionReducer.reduce(data, this.state);
|
this.permissionReducer.reduce(data, this.state);
|
||||||
this.metadataReducer.reduce(data, this.state);
|
this.metadataReducer.reduce(data, this.state);
|
||||||
|
@ -5,7 +5,7 @@ export default class ChatSubscription extends BaseSubscription {
|
|||||||
this.subscribe('/primary', 'chat-view');
|
this.subscribe('/primary', 'chat-view');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.subscribe('/synced', 'chat-hook');
|
this.subscribe('/synced', 'chat-hook');
|
||||||
this.subscribe('/primary', 'invite-view');
|
this.subscribe('/all', 'invite-store');
|
||||||
this.subscribe('/all', 'permission-store');
|
this.subscribe('/all', 'permission-store');
|
||||||
this.subscribe('/primary', 'contact-view');
|
this.subscribe('/primary', 'contact-view');
|
||||||
this.subscribe('/app-name/chat', 'metadata-store');
|
this.subscribe('/app-name/chat', 'metadata-store');
|
||||||
|
@ -2,7 +2,7 @@ import BaseSubscription from './base';
|
|||||||
|
|
||||||
export default class GlobalSubscription extends BaseSubscription {
|
export default class GlobalSubscription extends BaseSubscription {
|
||||||
start() {
|
start() {
|
||||||
this.subscribe('/primary', 'invite-view');
|
this.subscribe('/all', 'invite-store');
|
||||||
this.subscribe('/app-name/contacts', 'metadata-store');
|
this.subscribe('/app-name/contacts', 'metadata-store');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ export default class GroupsSubscription extends BaseSubscription {
|
|||||||
this.subscribe('/all', 'group-store');
|
this.subscribe('/all', 'group-store');
|
||||||
this.subscribe('/all', 'metadata-store');
|
this.subscribe('/all', 'metadata-store');
|
||||||
this.subscribe('/synced', 'contact-hook');
|
this.subscribe('/synced', 'contact-hook');
|
||||||
this.subscribe('/primary', 'invite-view');
|
this.subscribe('/all', 'invite-store');
|
||||||
this.subscribe('/all', 's3-store');
|
this.subscribe('/all', 's3-store');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import BaseSubscription from './base';
|
|||||||
export default class LaunchSubscription extends BaseSubscription {
|
export default class LaunchSubscription extends BaseSubscription {
|
||||||
start() {
|
start() {
|
||||||
this.subscribe('/all', 'launch');
|
this.subscribe('/all', 'launch');
|
||||||
|
this.subscribe('/weathertile', 'weather');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ export default class LinksSubscription extends BaseSubscription {
|
|||||||
start() {
|
start() {
|
||||||
this.subscribe('/all', 'group-store');
|
this.subscribe('/all', 'group-store');
|
||||||
this.subscribe('/primary', 'contact-view');
|
this.subscribe('/primary', 'contact-view');
|
||||||
this.subscribe('/primary', 'invite-view');
|
this.subscribe('/all', 'invite-store');
|
||||||
this.subscribe('/app-name/link', 'metadata-store');
|
this.subscribe('/app-name/link', 'metadata-store');
|
||||||
this.subscribe('/app-name/contacts', 'metadata-store');
|
this.subscribe('/app-name/contacts', 'metadata-store');
|
||||||
this.subscribe('/listening', 'link-listen-hook');
|
this.subscribe('/listening', 'link-listen-hook');
|
||||||
|
@ -5,7 +5,7 @@ export default class PublishSubscription extends BaseSubscription {
|
|||||||
this.subscribe('/primary', 'publish');
|
this.subscribe('/primary', 'publish');
|
||||||
this.subscribe('/all', 'group-store');
|
this.subscribe('/all', 'group-store');
|
||||||
this.subscribe('/primary', 'contact-view');
|
this.subscribe('/primary', 'contact-view');
|
||||||
this.subscribe('/primary', 'invite-view');
|
this.subscribe('/all', 'invite-store');
|
||||||
this.subscribe('/all', 'permission-store');
|
this.subscribe('/all', 'permission-store');
|
||||||
this.subscribe('/app-name/contacts', 'metadata-store');
|
this.subscribe('/app-name/contacts', 'metadata-store');
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user