mirror of
https://github.com/urbit/shrub.git
synced 2024-12-11 11:02:25 +03:00
Merge pull request #2410 from urbit/mp/os1/invite-launch
launch: subscribe to invite-view, show group invite count in tile
This commit is contained in:
commit
9d0fe998c1
@ -119,7 +119,7 @@ export class NewScreen extends Component {
|
||||
"focus-b--black focus-b--white-d"
|
||||
}
|
||||
rows={1}
|
||||
placeholder="Two trumpeteers and a microphone"
|
||||
placeholder="Two trumpeters and a microphone"
|
||||
style={{
|
||||
resize: "none",
|
||||
height: 48,
|
||||
|
@ -8,13 +8,36 @@ export default class ContactTile extends Component {
|
||||
render() {
|
||||
const { props } = this;
|
||||
|
||||
let data = _.get(props.data, "invites", false);
|
||||
let inviteNum = 0;
|
||||
|
||||
if (data && "/contacts" in data) {
|
||||
inviteNum = Object.keys(data["/contacts"]).length;
|
||||
}
|
||||
|
||||
let numNotificationsElem =
|
||||
inviteNum > 0 ? (
|
||||
<p
|
||||
className="absolute green2 white-d"
|
||||
style={{
|
||||
bottom: 6,
|
||||
fontWeight: 400,
|
||||
fontSize: 12,
|
||||
lineHeight: "20px"
|
||||
}}>
|
||||
{inviteNum > 99 ? "99+" : inviteNum}
|
||||
</p>
|
||||
) : (
|
||||
<div />
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={"w-100 h-100 relative bg-white bg-gray0-d " +
|
||||
"b--black b--gray1-d ba"}>
|
||||
<div
|
||||
className={
|
||||
"w-100 h-100 relative bg-white bg-gray0-d " + "b--black b--gray1-d ba"
|
||||
}>
|
||||
<a className="w-100 h-100 db pa2 bn" href="/~groups">
|
||||
<p
|
||||
className="black white-d absolute f9"
|
||||
style={{ left: 8, top: 8 }}>
|
||||
<p className="black white-d absolute f9" style={{ left: 8, top: 8 }}>
|
||||
Groups
|
||||
</p>
|
||||
<img
|
||||
@ -24,6 +47,7 @@ export default class ContactTile extends Component {
|
||||
width={48}
|
||||
height={48}
|
||||
/>
|
||||
{numNotificationsElem}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,8 +1,50 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Sigil } from './sigil';
|
||||
import _ from 'lodash';
|
||||
|
||||
export default class Header extends Component {
|
||||
render() {
|
||||
|
||||
let data = _.get(this.props.data, "invites", false);
|
||||
let inviteNum = 0;
|
||||
|
||||
if (data && "/contacts" in data) {
|
||||
inviteNum = Object.keys(data["/contacts"]).length;
|
||||
}
|
||||
|
||||
let numNotificationsElem =
|
||||
inviteNum > 0 ? (
|
||||
<a href="/~groups">
|
||||
<p
|
||||
className="absolute ph1 br2 ba b--gray2 green2 white-d f9 lh-solid"
|
||||
title={"Invitations to new groups"}
|
||||
style={{
|
||||
bottom: "-2",
|
||||
fontWeight: 600,
|
||||
fontSize: "8pt",
|
||||
padding: "0.15rem 0.4rem",
|
||||
right: 64
|
||||
}}>
|
||||
{inviteNum > 99 ? "99+" : inviteNum}
|
||||
</p>
|
||||
</a>
|
||||
) : (
|
||||
<a href="/~groups">
|
||||
<p
|
||||
className="absolute ph1 br2 ba b--gray2 gray2 white-d f9 lh-solid"
|
||||
title={"No new invitations to new groups"}
|
||||
style={{
|
||||
bottom: "-2",
|
||||
fontWeight: 600,
|
||||
fontSize: "8pt",
|
||||
padding: "0.15rem 0.4rem",
|
||||
right: 64
|
||||
}}>
|
||||
0
|
||||
</p>
|
||||
</a>
|
||||
);
|
||||
|
||||
return (
|
||||
<header
|
||||
className="bg-white bg-gray0-d w-100 justify-between relative tc pt3"
|
||||
@ -16,6 +58,7 @@ export default class Header extends Component {
|
||||
Home
|
||||
</span>
|
||||
<div className="absolute right-1 lh-copy" style={{ top: 12 }}>
|
||||
{numNotificationsElem}
|
||||
<Sigil
|
||||
ship={"~" + window.ship}
|
||||
size={16} color={"#000000"}
|
||||
|
@ -17,14 +17,25 @@ export default class Home extends Component {
|
||||
render() {
|
||||
let keys = [...this.props.keys];
|
||||
let tileElems = keys.map((tile) => {
|
||||
return (
|
||||
<Tile key={tile} type={tile} data={this.props.data[tile]} />
|
||||
);
|
||||
let tileData = {};
|
||||
if (tile in this.props.data && tile !== "invites") {
|
||||
tileData = this.props.data[tile] !== null
|
||||
? this.props.data[tile] : {};
|
||||
|
||||
tileData["invites"] = ("invites" in this.props.data)
|
||||
? this.props.data["invites"] : {};
|
||||
}
|
||||
return <Tile key={tile} type={tile} data={tileData} />;
|
||||
});
|
||||
|
||||
let headerData = {};
|
||||
if ("invites" in this.props.data) {
|
||||
headerData["invites"] = this.props.data["invites"];
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fl w-100 h-100 bg-white bg-gray0-d center">
|
||||
<Header />
|
||||
<Header data={headerData}/>
|
||||
<div className={"v-mid pa2 dtc-m dtc-l dtc-xl " +
|
||||
"flex justify-between flex-wrap"}
|
||||
style={{maxWidth: "40rem"}}>
|
||||
|
55
pkg/interface/launch/src/js/reducers/invite.js
Normal file
55
pkg/interface/launch/src/js/reducers/invite.js
Normal file
@ -0,0 +1,55 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
export class InviteReducer {
|
||||
reduce(json, state) {
|
||||
let data = _.get(json, "invite-initial", false);
|
||||
if (data) {
|
||||
state.invites = data;
|
||||
}
|
||||
|
||||
data = _.get(json, "invite-update", false);
|
||||
if (data) {
|
||||
this.create(data, state);
|
||||
this.delete(data, state);
|
||||
this.invite(data, state);
|
||||
this.accepted(data, state);
|
||||
this.decline(data, state);
|
||||
}
|
||||
}
|
||||
|
||||
create(json, state) {
|
||||
let data = _.get(json, "create", false);
|
||||
if (data) {
|
||||
state.invites[data.path] = {};
|
||||
}
|
||||
}
|
||||
|
||||
delete(json, state) {
|
||||
let data = _.get(json, "delete", false);
|
||||
if (data) {
|
||||
delete state.invites[data.path];
|
||||
}
|
||||
}
|
||||
|
||||
invite(json, state) {
|
||||
let data = _.get(json, "invite", false);
|
||||
if (data) {
|
||||
state.invites[data.path][data.uid] = data.invite;
|
||||
}
|
||||
}
|
||||
|
||||
accepted(json, state) {
|
||||
let data = _.get(json, "accepted", false);
|
||||
if (data) {
|
||||
console.log(data);
|
||||
delete state.invites[data.path][data.uid];
|
||||
}
|
||||
}
|
||||
|
||||
decline(json, state) {
|
||||
let data = _.get(json, "decline", false);
|
||||
if (data) {
|
||||
delete state.invites[data.path][data.uid];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,12 @@
|
||||
import { InviteReducer } from '/reducers/invite.js';
|
||||
|
||||
class Store {
|
||||
constructor() {
|
||||
this.state = {};
|
||||
this.state = {
|
||||
invites: {}
|
||||
};
|
||||
this.setState = () => {};
|
||||
this.inviteReducer = new InviteReducer();
|
||||
}
|
||||
|
||||
setStateHandler(setState) {
|
||||
@ -10,9 +14,14 @@ class Store {
|
||||
}
|
||||
|
||||
handleEvent(data) {
|
||||
if (("from" in data) && data.from.app === "invite-view") {
|
||||
this.inviteReducer.reduce(data.data, this.state)
|
||||
}
|
||||
else {
|
||||
let json = data.data;
|
||||
|
||||
this.setState(json);
|
||||
}
|
||||
this.setState(this.state);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,11 @@ export class Subscription {
|
||||
this.handleEvent.bind(this),
|
||||
this.handleError.bind(this),
|
||||
ship);
|
||||
}
|
||||
api.bind("invite-view", '/primary',
|
||||
this.handleEvent.bind(this),
|
||||
this.handleError.bind(this),
|
||||
ship);
|
||||
}
|
||||
|
||||
handleEvent(diff) {
|
||||
store.handleEvent(diff);
|
||||
|
Loading…
Reference in New Issue
Block a user