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"
|
"focus-b--black focus-b--white-d"
|
||||||
}
|
}
|
||||||
rows={1}
|
rows={1}
|
||||||
placeholder="Two trumpeteers and a microphone"
|
placeholder="Two trumpeters and a microphone"
|
||||||
style={{
|
style={{
|
||||||
resize: "none",
|
resize: "none",
|
||||||
height: 48,
|
height: 48,
|
||||||
|
@ -8,13 +8,36 @@ export default class ContactTile extends Component {
|
|||||||
render() {
|
render() {
|
||||||
const { props } = this;
|
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 (
|
return (
|
||||||
<div className={"w-100 h-100 relative bg-white bg-gray0-d " +
|
<div
|
||||||
"b--black b--gray1-d ba"}>
|
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">
|
<a className="w-100 h-100 db pa2 bn" href="/~groups">
|
||||||
<p
|
<p className="black white-d absolute f9" style={{ left: 8, top: 8 }}>
|
||||||
className="black white-d absolute f9"
|
|
||||||
style={{ left: 8, top: 8 }}>
|
|
||||||
Groups
|
Groups
|
||||||
</p>
|
</p>
|
||||||
<img
|
<img
|
||||||
@ -24,6 +47,7 @@ export default class ContactTile extends Component {
|
|||||||
width={48}
|
width={48}
|
||||||
height={48}
|
height={48}
|
||||||
/>
|
/>
|
||||||
|
{numNotificationsElem}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,8 +1,50 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Sigil } from './sigil';
|
import { Sigil } from './sigil';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
export default class Header extends Component {
|
export default class Header extends Component {
|
||||||
render() {
|
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 (
|
return (
|
||||||
<header
|
<header
|
||||||
className="bg-white bg-gray0-d w-100 justify-between relative tc pt3"
|
className="bg-white bg-gray0-d w-100 justify-between relative tc pt3"
|
||||||
@ -16,6 +58,7 @@ export default class Header extends Component {
|
|||||||
Home
|
Home
|
||||||
</span>
|
</span>
|
||||||
<div className="absolute right-1 lh-copy" style={{ top: 12 }}>
|
<div className="absolute right-1 lh-copy" style={{ top: 12 }}>
|
||||||
|
{numNotificationsElem}
|
||||||
<Sigil
|
<Sigil
|
||||||
ship={"~" + window.ship}
|
ship={"~" + window.ship}
|
||||||
size={16} color={"#000000"}
|
size={16} color={"#000000"}
|
||||||
|
@ -17,14 +17,25 @@ export default class Home extends Component {
|
|||||||
render() {
|
render() {
|
||||||
let keys = [...this.props.keys];
|
let keys = [...this.props.keys];
|
||||||
let tileElems = keys.map((tile) => {
|
let tileElems = keys.map((tile) => {
|
||||||
return (
|
let tileData = {};
|
||||||
<Tile key={tile} type={tile} data={this.props.data[tile]} />
|
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 (
|
return (
|
||||||
<div className="fl w-100 h-100 bg-white bg-gray0-d center">
|
<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 " +
|
<div className={"v-mid pa2 dtc-m dtc-l dtc-xl " +
|
||||||
"flex justify-between flex-wrap"}
|
"flex justify-between flex-wrap"}
|
||||||
style={{maxWidth: "40rem"}}>
|
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 {
|
class Store {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.state = {};
|
this.state = {
|
||||||
|
invites: {}
|
||||||
|
};
|
||||||
this.setState = () => {};
|
this.setState = () => {};
|
||||||
|
this.inviteReducer = new InviteReducer();
|
||||||
}
|
}
|
||||||
|
|
||||||
setStateHandler(setState) {
|
setStateHandler(setState) {
|
||||||
@ -10,9 +14,14 @@ class Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleEvent(data) {
|
handleEvent(data) {
|
||||||
|
if (("from" in data) && data.from.app === "invite-view") {
|
||||||
|
this.inviteReducer.reduce(data.data, this.state)
|
||||||
|
}
|
||||||
|
else {
|
||||||
let json = data.data;
|
let json = data.data;
|
||||||
|
|
||||||
this.setState(json);
|
this.setState(json);
|
||||||
|
}
|
||||||
|
this.setState(this.state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,11 @@ export class Subscription {
|
|||||||
this.handleEvent.bind(this),
|
this.handleEvent.bind(this),
|
||||||
this.handleError.bind(this),
|
this.handleError.bind(this),
|
||||||
ship);
|
ship);
|
||||||
}
|
api.bind("invite-view", '/primary',
|
||||||
|
this.handleEvent.bind(this),
|
||||||
|
this.handleError.bind(this),
|
||||||
|
ship);
|
||||||
|
}
|
||||||
|
|
||||||
handleEvent(diff) {
|
handleEvent(diff) {
|
||||||
store.handleEvent(diff);
|
store.handleEvent(diff);
|
||||||
|
Loading…
Reference in New Issue
Block a user