Skip to content
This repository was archived by the owner on Oct 11, 2022. It is now read-only.
Merged

2.4.7 #3302

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
b4c3610
Add concierge page and section on pricing
brianlovin Jun 8, 2018
5099365
Fix apostrophe
brianlovin Jun 8, 2018
f887740
First pass at mobile toast system
brianlovin Jun 9, 2018
66f1d91
unset z-index on SelectedUserPills
mike-ap Jun 10, 2018
8f09769
Fix emails not sending to admins
brianlovin Jun 10, 2018
2446e66
Merge pull request #3285 from withspectrum/fix-hermes-emails-not-sending
brianlovin Jun 10, 2018
7017630
Implement react-hot-loader
mxstbr Jun 11, 2018
18e4c7d
Move time formatting utils to shared
mxstbr Jun 11, 2018
1a690d6
Dynamically update dm thread title on mobiel
mxstbr Jun 11, 2018
618f6db
Dynamic Thread screen title on mobile
mxstbr Jun 11, 2018
da6fe39
Dynamic community view title on mobile
mxstbr Jun 11, 2018
b8e4325
Dynamic title on channel on mobile
mxstbr Jun 11, 2018
364ef31
Cleanup user dynamic title on mobile
mxstbr Jun 11, 2018
b68ed58
Move client analytics helpers to shared/, make them work with mobile
mxstbr Jun 11, 2018
88a7dcd
Dynamically pass the client to shared amplitude utils
mxstbr Jun 11, 2018
d982fec
Add note about getInstance
mxstbr Jun 11, 2018
6e37aeb
Cleanup analytics helpers so they actually work on mobile
mxstbr Jun 11, 2018
ae7a0f9
Fix imports so web client works
mxstbr Jun 11, 2018
153c46f
Track channel views
mxstbr Jun 11, 2018
e76ca6b
Track community views on mobile
mxstbr Jun 11, 2018
466567a
Track DM thread views
mxstbr Jun 11, 2018
e1aaaec
Track direct message list views
mxstbr Jun 11, 2018
80fad85
Track dashboard and login views
mxstbr Jun 11, 2018
2d02f18
Track mobile thread views
mxstbr Jun 11, 2018
2bd0de5
Merge pull request #3286 from withspectrum/rhl
brianlovin Jun 11, 2018
130a510
Merge pull request #3284 from mike-ap/fix-notification-dropdown-with-…
brianlovin Jun 11, 2018
b9fea81
Merge pull request #3287 from withspectrum/mobile-cleanup
brianlovin Jun 11, 2018
960bdd1
Merge pull request #3291 from withspectrum/mobile-amplitude-analytics
brianlovin Jun 11, 2018
7cb9e31
Merge alpha and fix conflicts
brianlovin Jun 11, 2018
aad1630
Merge pull request #3292 from withspectrum/track-mobile-amplitude-events
brianlovin Jun 11, 2018
1ba5fe2
Merge branch 'alpha' of github.com:withspectrum/spectrum into mobile-…
brianlovin Jun 11, 2018
1518fce
Clarify the tab bar when in dev or prod mode
brianlovin Jun 11, 2018
949553c
Cleanup flow and reducers since we dont need timeout in action
brianlovin Jun 11, 2018
d70a4b4
Clean up and simplify toast system
brianlovin Jun 11, 2018
14d262c
Tuned animation
brianlovin Jun 12, 2018
c84280d
Fix peril
brianlovin Jun 12, 2018
a34797e
Fix flow
brianlovin Jun 12, 2018
064c580
Fix some icons, new tab bar icons
brianlovin Jun 12, 2018
103c987
Fix and reduce data load in loading admin dash
brianlovin Jun 12, 2018
4883e1f
Fix chronos
brianlovin Jun 12, 2018
04e2c01
Merge pull request #3295 from withspectrum/fix-admin-dash
brianlovin Jun 12, 2018
63697c2
Merge pull request #3294 from withspectrum/fix-mobile-icons
mxstbr Jun 12, 2018
31ab6e8
Merge pull request #3283 from withspectrum/mobile-toasts
mxstbr Jun 12, 2018
3613357
minor copy updates
superbryntendo Jun 12, 2018
24627bc
removes concierge description that was directly above the in-depth co…
superbryntendo Jun 12, 2018
ce8bf5a
adds link to blog post to concierge component
superbryntendo Jun 12, 2018
ca3064d
Merge branch 'alpha' of github.com:withspectrum/spectrum into concier…
brianlovin Jun 12, 2018
8d3c913
Fix test
brianlovin Jun 12, 2018
1593726
Eslint fix
brianlovin Jun 12, 2018
473d533
gets rid of full-width cards on mobile
superbryntendo Jun 12, 2018
b205492
Merge pull request #3251 from withspectrum/concierge-page
brianlovin Jun 12, 2018
db9a876
Merge branch 'alpha' of github.com:withspectrum/spectrum into 2.4.7
brianlovin Jun 12, 2018
1e1682f
Version
brianlovin Jun 12, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion analytics/utils/transformations.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {
DBMessage,
DBUsersThreads,
} from 'shared/types';
import { getTruthyValuesFromObject } from './truthy-values';
import { getTruthyValuesFromObject } from 'shared/truthy-values';

type AnalyticsChannel = {
id: ?string,
Expand Down
8 changes: 7 additions & 1 deletion api/models/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ export const getAu = (range: Timeframe) => {
const { current } = parseRange(range);
return db
.table('users')
.filter(db.row('lastSeen').during(db.now().sub(current), db.now()))
.filter(row =>
row
.hasFields('lastSeen')
.and(row('lastSeen').during(db.now().sub(current), db.now()))
)
.count()
.default(0)
.run();
Expand Down Expand Up @@ -102,6 +106,8 @@ export const getCount = (table: string, filter: mixed) => {
export const getCoreMetrics = () => {
return db
.table('coreMetrics')
.orderBy(db.desc('date'))
.limit(90)
.orderBy('date')
.run();
};
6 changes: 5 additions & 1 deletion chronos/models/coreMetrics.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ export const getAu = (range: string) => {
const RANGE = parseRange(range);
return db
.table('users')
.filter(db.row('lastSeen').during(db.now().sub(RANGE), db.now()))
.filter(row =>
row
.hasFields('lastSeen')
.and(row('lastSeen').during(db.now().sub(RANGE), db.now()))
)
.count()
.default(0)
.run();
Expand Down
8 changes: 6 additions & 2 deletions chronos/models/usersSettings.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@ export const getUsersForDigest = (
// save some processing time by making sure the user has a username
.filter(row => row.hasFields('username').and(row('username').ne(null)))
// save some processing time by making sure the user was active in the last month
.filter(
db.row('lastSeen').during(db.now().sub(60 * 60 * 24 * 30), db.now())
.filter(row =>
row
.hasFields('lastSeen')
.and(
row('lastSeen').during(db.now().sub(60 * 60 * 24 * 30), db.now())
)
)
.pluck(['userId', 'email', 'firstName', 'name', 'username'])
.distinct()
Expand Down
20 changes: 9 additions & 11 deletions config-overrides.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const debug = require('debug')('build:config-overrides');
const webpack = require('webpack');
const { injectBabelPlugin } = require('react-app-rewired');
const rewireStyledComponents = require('react-app-rewire-styled-components');
const rewireReactHotLoader = require('react-app-rewire-hot-loader');
const swPrecachePlugin = require('sw-precache-webpack-plugin');
const fs = require('fs');
const path = require('path');
Expand Down Expand Up @@ -74,15 +75,19 @@ const transpileShared = config => {
module.exports = function override(config, env) {
if (process.env.NODE_ENV === 'development') {
config.output.path = path.join(__dirname, './build');
config = rewireReactHotLoader(config, env);
config.plugins.push(
WriteFilePlugin({
log: true,
useHashIndex: false,
})
);
}
config.plugins.push(
new ReactLoadablePlugin({
filename: './build/react-loadable.json',
})
);
if (process.env.NODE_ENV === 'production') {
removeEslint(config);
}
config = injectBabelPlugin('react-loadable/babel', config);
config = transpileShared(config);
// Filter the default serviceworker plugin, add offline plugin instead
Expand Down Expand Up @@ -126,14 +131,6 @@ module.exports = function override(config, env) {
if (process.env.BUNDLE_BUDDY === 'true') {
config.plugins.push(new BundleBuddyWebpackPlugin());
}
if (process.env.NODE_ENV === 'development') {
config.plugins.push(
WriteFilePlugin({
log: true,
useHashIndex: false,
})
);
}
config.plugins.unshift(
new webpack.optimize.CommonsChunkPlugin({
names: ['bootstrap'],
Expand All @@ -142,6 +139,7 @@ module.exports = function override(config, env) {
})
);
if (process.env.NODE_ENV === 'production') {
removeEslint(config);
config.plugins.push(
new webpack.DefinePlugin({
'process.env': {
Expand Down
9 changes: 9 additions & 0 deletions cypress/integration/concierge_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
describe('Renders conceirge page ', () => {
beforeEach(() => {
cy.visit(`/pricing/concierge`);
});

it('should render key conceirge page components', () => {
cy.get('[data-cy="concierge-page"]').should('be.visible');
});
});
18 changes: 18 additions & 0 deletions flow-typed/npm/electron-context-menu_vx.x.x.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// flow-typed signature: fa2daa44307abd285e881b992fa9d76c
// flow-typed version: <<STUB>>/electron-context-menu_v0.9.1/flow_v0.66.0

/**
* This is an autogenerated libdef stub for:
*
* 'electron-context-menu'
*
* Fill this stub out by replacing all the `any` types.
*
* Once filled out, we encourage you to share your work with the
* community by sending a pull request to:
* https://github.com/flowtype/flow-typed
*/

declare module 'electron-context-menu' {
declare module.exports: any;
}
17 changes: 0 additions & 17 deletions hermes/send-email.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,23 +59,6 @@ const sendEmail = (options: Options) => {
return;
}

if (!isEmail(To)) {
if (userId) {
trackQueue.add({
userId: userId,
event: events.EMAIL_BOUNCED,
// we can safely log the To field because it's not a valid email, thus not PII
properties: {
tag: Tag,
to: To,
error: 'To field was not a valid email address',
},
});
}

return;
}

// $FlowFixMe
return new Promise((res, rej) => {
client.sendEmailWithTemplate(
Expand Down
11 changes: 7 additions & 4 deletions mobile/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ import Sentry from 'sentry-expo';
import React, { Fragment } from 'react';
import { StatusBar } from 'react-native';
import { SecureStore, AppLoading } from 'expo';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import { ApolloProvider } from 'react-apollo';
import { ThemeProvider } from 'styled-components';
import { ActionSheetProvider } from '@expo/react-native-action-sheet';
import { type ApolloClient } from 'apollo-client';
import { initStore } from './reducers/store';

import Toasts from './components/Toasts';
import theme from '../shared/theme';
import { createClient } from '../shared/graphql';
import Login from './components/Login';
import TabBar from './views/TabBar';
import reducers from './reducers';
import { authenticate } from './actions/authentication';

let sentry = Sentry.config(
Expand All @@ -24,7 +24,7 @@ let sentry = Sentry.config(
// Need to guard this for HMR to work
if (sentry && sentry.install) sentry.install();

export const store = createStore(reducers);
export const store = initStore();

type State = {
authLoaded: ?boolean,
Expand Down Expand Up @@ -61,7 +61,9 @@ class App extends React.Component<{}, State> {
};

listen = () => {
const { authentication } = store.getState();
const storeState = store.getState();
// $FlowFixMe
const authentication = storeState && storeState.authentication;
const { token: oldToken } = this.state;
if (authentication.token !== oldToken) {
this.setState({
Expand Down Expand Up @@ -89,6 +91,7 @@ class App extends React.Component<{}, State> {
<ActionSheetProvider>
<Fragment>
<StatusBar barStyle={'default'} />
<Toasts />
{!token ? <Login /> : <TabBar />}
</Fragment>
</ActionSheetProvider>
Expand Down
42 changes: 42 additions & 0 deletions mobile/actions/toasts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// @flow
import type { Dispatch } from 'redux';
import type { GlyphTypes } from '../components/Icon/types';

type ToastTypes = 'notification' | 'success' | 'error' | 'neutral';

export type AddToastType = {
type: ToastTypes,
message: string,
onPressHandler: Function,
icon?: ?GlyphTypes,
};

export type ToastType = {
...$Exact<AddToastType>,
id: number,
};

export type AddToastActionType = {
type: 'ADD_TOAST',
payload: {
...$Exact<ToastType>,
},
};

let nextToastId = 0;
export const addToast = (payload: AddToastType) => (
dispatch: Dispatch<Object>
) => {
const id = nextToastId++;
return dispatch({
type: 'ADD_TOAST',
payload: {
id,
...payload,
},
});
};

export const removeToast = (id: number) => {
return { type: 'REMOVE_TOAST', payload: { id } };
};
2 changes: 1 addition & 1 deletion mobile/components/ChatInput/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class ChatInput extends React.Component<InputProps, State> {
onSubmitEditing={this.submit}
/>
</ChatInputTextInputWrapper>
<Icon glyph={'send'} onPress={this.submit} size={32} />
<Icon glyph={'send-fill'} onPress={this.submit} size={32} />
</ChatInputWrapper>
{/* NOTE(@mxstbr): Magic number, otherwise the chatinput is way above the keyboard */}
<KeyboardSpacer topSpacing={-75} />
Expand Down
3 changes: 3 additions & 0 deletions mobile/components/Icon/glyphs.js
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,7 @@ export default (glyph: GlyphTypes, color: string) => {
return (
<Fragment>
<Path
fillRule="evenodd"
fill={color}
d="M9,8l0,5.287l7.054,1.495c0.628,0.133 0.966,0.665 0.989,1.164c0,0.009 0.001,0.022 0.001,0.034c0,0.004 0,0.008 0,0.012c0,0.005 0,0.009 0,0.013c0,0.012 -0.001,0.025 -0.001,0.034c-0.023,0.498 -0.361,1.031 -0.989,1.164l-7.054,1.495l0,5.627c0.02,0.001 0.049,-0.002 0.09,-0.017c4.386,-1.524 15.41,-7.808 15.41,-8.308c0,-0.5 -11.075,-6.473 -15.41,-7.984c-0.041,-0.014 -0.07,-0.017 -0.09,-0.016Zm17.555,7.992l0,-0.011l0,-0.003c-0.011,-0.698 -0.39,-1.289 -0.925,-1.685c-3.631,-2.688 -11.512,-6.642 -15.882,-8.165c-0.624,-0.218 -1.3,-0.158 -1.843,0.185c-0.554,0.349 -0.905,0.958 -0.905,1.667l0,5.712c0,0.708 0.496,1.32 1.189,1.467l3.931,0.833l-3.931,0.834c-0.693,0.146 -1.189,0.758 -1.189,1.467l0,6.052c0,0.709 0.351,1.317 0.905,1.667c0.543,0.343 1.219,0.403 1.843,0.185c4.371,-1.527 12.29,-5.85 15.881,-8.505c0.536,-0.397 0.915,-0.987 0.925,-1.685l0,-0.003l0.001,-0.012Z"
/>
Expand All @@ -836,6 +837,8 @@ export default (glyph: GlyphTypes, color: string) => {
return (
<Fragment>
<Path
fillRule="evenodd"
clipRule="evenodd"
fill={color}
d="M16.044,15.012c-0.005,-0.104 -0.071,-0.205 -0.198,-0.232l-7.45,-1.579c-0.231,-0.049 -0.396,-0.253 -0.396,-0.489l0,-5.712c0,-0.73 0.698,-1.159 1.419,-0.908c4.295,1.497 12.081,5.408 15.616,8.025c0.34,0.252 0.515,0.573 0.52,0.895c-0.005,0.323 -0.18,0.644 -0.52,0.896c-3.535,2.617 -11.321,6.868 -15.616,8.365c-0.721,0.251 -1.419,-0.178 -1.419,-0.908l0,-6.052c0,-0.236 0.165,-0.44 0.396,-0.489l7.45,-1.579c0.127,-0.027 0.193,-0.129 0.198,-0.233Z"
/>
Expand Down
44 changes: 42 additions & 2 deletions mobile/components/Lists/ThreadListItem/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @flow
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Share } from 'react-native';
import { connectActionSheet } from '@expo/react-native-action-sheet';
import compose from 'recompose/compose';
Expand All @@ -20,6 +21,7 @@ import deleteThreadMutation, {
} from '../../../../shared/graphql/mutations/thread/deleteThread';
import pinThreadMutation from '../../../../shared/graphql/mutations/community/pinCommunityThread';
import triggerDeleteAlert from '../../DeleteAlert';
import { addToast } from '../../../actions/toasts';

type Props = {
thread: GetThreadType,
Expand All @@ -33,6 +35,7 @@ type Props = {
pinThread: Function,
deleteThread: Function,
toggleThreadNotifications: Function,
dispatch: Function,
// refetches the parent query that resolved this thread - used when
// a thread is deleted and we want to refetch the parent query, regardless
// of where that query was called from
Expand Down Expand Up @@ -75,12 +78,48 @@ class ThreadListItemHandlers extends Component<Props> {
};

toggleLockThread = () => {
const { thread, setThreadLock } = this.props;
const { thread, setThreadLock, dispatch, navigation } = this.props;

return setThreadLock({
threadId: thread.id,
value: !thread.isLocked,
});
})
.then(() => {
return dispatch(
addToast({
type: 'neutral',
message: thread.isLocked
? 'Conversation unlocked'
: 'Conversation locked',
onPressHandler: () =>
navigation.navigate({
routeName: 'Thread',
key: thread.id,
params: {
id: thread.id,
},
}),
icon: 'checkmark',
})
);
})
.catch(err => {
return dispatch(
addToast({
type: 'error',
message: 'Unable to lock conversation',
onPressHandler: () =>
navigation.navigate({
routeName: 'Thread',
key: thread.id,
params: {
id: thread.id,
},
}),
icon: 'checkmark',
})
);
});
};

togglePinThread = () => {
Expand Down Expand Up @@ -295,6 +334,7 @@ class ThreadListItemHandlers extends Component<Props> {
}

export const ThreadListItem = compose(
connect(),
setThreadLockMutation,
deleteThreadMutation,
pinThreadMutation,
Expand Down
6 changes: 6 additions & 0 deletions mobile/components/Login/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
CodeOfConduct,
Link,
} from './style';
import { events, track } from '../../utils/analytics';

const API_URL =
process.env.NODE_ENV === 'production'
Expand All @@ -30,7 +31,12 @@ type Props = {
};

class Login extends React.Component<Props> {
componentDidMount() {
track(events.LOGIN_PAGE_VIEWED);
}

authenticate = (provider: Provider) => async () => {
track(events.LOGIN_PAGE_AUTH_CLICKED, { provider });
const redirectUrl = AuthSession.getRedirectUrl();
const result = await AuthSession.startAsync({
authUrl: `${API_URL}/auth/${provider}?r=${redirectUrl}&authType=token`,
Expand Down
2 changes: 1 addition & 1 deletion mobile/components/Messages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Message from '../Message';
import InfiniteList from '../InfiniteList';
import { ThreadMargin } from '../../views/Thread/style';
import { sortAndGroupMessages } from '../../../shared/clients/group-messages';
import { convertTimestampToDate } from '../../../src/helpers/utils';
import { convertTimestampToDate } from '../../../shared/time-formatting';
import { withCurrentUser } from '../../components/WithCurrentUser';
import RoboText from './RoboText';
import Author from './Author';
Expand Down
Loading