Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,53 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:build="http://schemas.microsoft.com/developer/appx/2015/build" IgnorableNamespaces="uap mp build">
<Identity Name="INSERT-YOUR-PACKAGE-IDENTITY-NAME-HERE" Publisher="CN=INSERT-YOUR-PACKAGE-IDENTITY-PUBLISHER-HERE" Version="1.0.0.0" ProcessorArchitecture="neutral"/>
<mp:PhoneIdentity PhoneProductId="46fbef95-c50c-d1ac-a95a-e921b0017976" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>

<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:build="http://schemas.microsoft.com/developer/appx/2015/build" IgnorableNamespaces="uap mp build">
<Identity Name="INSERT-YOUR-PACKAGE-IDENTITY-NAME-HERE" Publisher="CN=INSERT-YOUR-PACKAGE-IDENTITY-PUBLISHER-HERE" Version="1.0.0.0" ProcessorArchitecture="neutral"/>
<mp:PhoneIdentity PhoneProductId="46fbef95-c50c-d1ac-a95a-e921b0017976" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<build:Metadata>
<build:Item Name="GenerationTool" Version="pwabuilder"/>
<build:Item Name="GenerationToolVersion" Version="2.0.3-rc.0"/>
<build:Item Name="PlatformId" Value="windows10"/>
<build:Item Name="PlatformPackage" Value="pwabuilder-windows10"/>
<build:Item Name="PlatformVersion" Version="2.0.3-rc.1"/>
<build:Item Name="PlatformId" Value="windows10"/>
<build:Item Name="PlatformPackage" Value="pwabuilder-windows10"/>
<build:Item Name="PlatformVersion" Version="2.0.3-rc.1"/>
<build:Item Name="GeneratedFrom" Value="CLI"/>
<build:Item Name="GenerationDate" Value="2018-05-08 02:17:51 Z"/>
</build:Metadata>

<Properties>
<DisplayName>BUILD2018DEMO</DisplayName>
<PublisherDisplayName>Microsoft</PublisherDisplayName>
<Logo>images\StoreLogo.png</Logo>
</Properties>

<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.10240.0" MaxVersionTested="10.0.10240.0"/>
</Dependencies>

<Properties>
<DisplayName>BUILD2018DEMO</DisplayName>
<PublisherDisplayName>Microsoft</PublisherDisplayName>
<Logo>images\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.10240.0" MaxVersionTested="10.0.10240.0"/>
</Dependencies>
<Resources>
<Resource Language="en-us"/>
</Resources>

<Applications>
<Application Id="BUILD2018DEMO" StartPage="http://localhost:5000/">
<uap:VisualElements DisplayName="BUILD2018DEMO" Square150x150Logo="images\Square150x150Logo.png" Square44x44Logo="images\Square44x44Logo.png" Description="BUILD 2018 Goat Demo" BackgroundColor="#FFFFFF">



<uap:InitialRotationPreference>
<uap:Rotation Preference="portrait"/>
</uap:InitialRotationPreference>
</uap:VisualElements>
<Resource Language="en-us"/>
</Resources>
<Applications>
<Application Id="BUILD2018DEMO" StartPage="http://localhost:5000/">
<uap:VisualElements DisplayName="BUILD2018DEMO" Square150x150Logo="images\Square150x150Logo.png" Square44x44Logo="images\Square44x44Logo.png" Description="BUILD 2018 Goat Demo" BackgroundColor="#FFFFFF">
<uap:InitialRotationPreference>
<uap:Rotation Preference="portrait"/>
</uap:InitialRotationPreference>
</uap:VisualElements>
<uap:ApplicationContentUriRules>
<uap:Rule Type="include" WindowsRuntimeAccess="none" Match="https://*"/>

<uap:Rule Type="include" WindowsRuntimeAccess="all" Match="http://localhost:5000/"/>
</uap:ApplicationContentUriRules>
</Application>
</Applications>

<Extensions>
<uap:Extension Category="windows.protocol">
<uap:Protocol Name="build-2018-demo">
<uap:DisplayName>BUILD2018DEMO</uap:DisplayName>
</uap:Protocol>
</uap:Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient"/>

</Capabilities>

</Package>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 31 additions & 12 deletions dev/demo-app/webapp/ClientApp/boot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import * as Notifications from './services/notifications';
import * as ServiceWorker from './services/serviceWorker';
import * as LockScreen from './services/lockScreen';
import * as GraphServices from './services/graphServices';
import * as AppMode from './services/appMode';

function renderApp() {
// This code starts up the React app when it runs in a browser. It sets up the routing
Expand All @@ -34,11 +35,11 @@ ServiceWorker.init().then(() =>
Notifications.register());

// Demo Mode toggler
let demoMode = window.localStorage.getItem('demoMode') === 'enabled';
let demoMode = AppMode.isDemoMode();
window.addEventListener('keyup', (e: any) => {
if(e.key && e.key.toLowerCase() === 'd' && e.shiftKey) {
let newMode = demoMode ? 'disabled' : 'enabled';
window.localStorage.setItem('demoMode', newMode);
let newMode = demoMode ? AppMode.modes.DISABLED : AppMode.modes.ENABLED;
AppMode.setMode(newMode);
alert('Demo mode "' + newMode + '"');
window.location.reload(true);
}
Expand Down Expand Up @@ -90,26 +91,34 @@ if (demoMode) {
// Retrieve calendar
let appointmentsPromise = GraphServices.instances.calendar.retrieveCalendarForToday();


// Update calendar UI
appointmentsPromise.then(appointments => CalendarStore.instance.reset(appointments));
appointmentsPromise.then(appointments => {
console.log('Your current appointments:', appointments);
CalendarStore.instance.reset(appointments);
});

// Check for long meeting and add yoga session
appointmentsPromise.then(appointments => {
var meetings = appointments.filter(m => m.duration && m.duration > meetingDurationThreshold);
if (meetings.length) {
GraphServices.instances.calendar.addRelaxationEventsAfter(meetings)
let relaxationEventSubject = 'Goat Yoga session';
let longMeetings = appointments.filter(m => m.duration && m.duration > meetingDurationThreshold);

let meetingsNotChecked = longMeetings.filter(m => !appointments.find(a => a.details === relaxationEventSubject && a.from === m.to));

if (meetingsNotChecked.length) {
GraphServices.instances.calendar.addRelaxationEventsAfter(meetingsNotChecked, relaxationEventSubject)
.then(relaxationEvents => {
relaxationEvents.forEach(m => {
let relax = Object.assign({}, m, { type: 'relax showInsightTwo', insight: true});
let relax = Object.assign({}, m, { type: 'relax showInsightTwo', insight: true });
CalendarStore.instance.add(relax);
});
});
}
})
});

// Subscribe for 'email sent' notifications
// Create PushNotification channel, and use deviceId as clientState for the notification
// When backend recieved notification, the deviceId will be enough to direct the notification to this device
// Subscribe for 'email sent' notifications.
// Create PushNotification channel, and use deviceId as clientState for the notification.
// When backend recievs the Microsoft Graph notification, the deviceId will be enough to direct the notification to this device.
Notifications.registerNativePushNotification().then(deviceId => {
if (!deviceId) return console.log('Could not register PushNotification channel. Non-native medium?');

Expand All @@ -126,6 +135,16 @@ renderApp();
declare var Windows: any;
if (typeof Windows !== 'undefined') {
document.body.classList.add('showOne')

//Register onActivated for timeline activities
Windows.UI.WebUI.WebUIApplication.onactivated = (eventArgs) => {
console.log("activated via " + eventArgs.detail[0].kind + ". " + JSON.stringify(eventArgs.detail[0].uri));
if (eventArgs.detail[0].uri && eventArgs.detail[0].uri.path) {
let path: string = eventArgs.detail[0].uri.path;
path = path.substring(0, path.lastIndexOf('.'));
window.location.replace(window.location.protocol + "//" + window.location.host + path);
}
};
}

// Allow Hot Module Replacement
Expand Down
35 changes: 20 additions & 15 deletions dev/demo-app/webapp/ClientApp/components/Calendar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { withRouter, RouteComponentProps } from 'react-router-dom'
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { Listener } from 'events';

import * as CalendarModel from '../models/calendar';
Expand All @@ -14,10 +14,17 @@ export interface AppointmentCalendarState {

export class AppointmentCalendar extends React.Component<{}, AppointmentCalendarState> {
_handleStoreUpdate: Listener;
_scheduleRef: any;
_setScheduleRef: any;
constructor() {
super();
this.state = { appointments: store.get() };
this._handleStoreUpdate = this.onStoreUpdate.bind(this);
this._scheduleRef = null;

this._setScheduleRef = element => {
this._scheduleRef = element;
};
}

componentWillMount() {
Expand All @@ -36,23 +43,21 @@ export class AppointmentCalendar extends React.Component<{}, AppointmentCalendar
});
}

public render() {
componentDidUpdate() {
if(!this.state.newAppointment || !this._scheduleRef) {
return;
}

let rows = CalendarModel.appointmentsToRows(1000, 1800, this.state.appointments);
let newRoxIx = rows.findIndex(r => r.appointments.indexOf(this.state.newAppointment as CalendarModel.CalendarAppointment) > -1);
let divIx = newRoxIx * 4;
this._scheduleRef.children[divIx].scrollIntoView();
}

// HACK
if (this.state.newAppointment) {
let newRoxIx = rows.findIndex(r => r.appointments.indexOf(this.state.newAppointment as CalendarModel.CalendarAppointment) > -1);
let divIx = newRoxIx * 4;
setTimeout(() => {
let schedule = document.getElementById('schedule');
if (!schedule) return;
schedule.children[divIx].scrollIntoView({
behavior: 'smooth'
});
}, 150);
}
public render() {
let rows = CalendarModel.appointmentsToRows(1000, 1800, this.state.appointments);

return (<div className="insight" id="schedule">
return (<div className="insight" id="schedule" ref={this._setScheduleRef}>
{rows.map(r => asRow(r))}
</div>);
}
Expand Down
26 changes: 20 additions & 6 deletions dev/demo-app/webapp/ClientApp/components/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,33 @@ export class DashboardState {
}

export class Dashboard extends React.Component<RouteComponentProps<{}>, DashboardState> {
constructor() {
super();
this.state = { isOpen: false }
constructor(props) {
super(props);
this.state = this.loadPicture(props) || { isOpen: false };
}

openPic(pic: string) {

this.setState({
this.setState(this.generateOpenPicState(pic));

const activityId = new Date().getTime() + "_picture_" + pic;

Timeline.createTimelineActivity(activityId, 'Oh! A Goat!', pic);
}

generateOpenPicState(pic: string) {
return {
isOpen: true,
selectedPicture: pic
});
};
}

Timeline.createTimelineActivity('picture', 'Oh! A Goat!', pic);
loadPicture(props) {
if (props.location.pathname && props.location.pathname.includes("images")) {
const pic: string = goatPics.find((goatPic) => goatPic.includes(props.location.pathname)) || "";
return this.generateOpenPicState(pic);
}
return null;
}

public render() {
Expand Down
3 changes: 2 additions & 1 deletion dev/demo-app/webapp/ClientApp/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from 'react';
import { Link, NavLink } from 'react-router-dom';

import * as UserAuth from '../services/userAuth';
import * as AppModes from '../services/appMode';

import { AppointmentCalendar } from './Calendar';

Expand All @@ -16,7 +17,7 @@ export class Header extends React.Component<{}, HeaderState> {
constructor() {
super();

let demoMode = window.localStorage.getItem('demoMode') === 'enabled';
let demoMode = AppModes.isDemoMode();

if (demoMode) {
// DEMO MODE
Expand Down
9 changes: 5 additions & 4 deletions dev/demo-app/webapp/ClientApp/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ import { VideoPlayer } from './components/VideoPlayer';

export const routes = <div>
<RouteWithLayout layout={Layout} exact path='/' component={ Dashboard } />
<RouteWithLayout layout={EmptyLayout} path='/video' component={ VideoPlayer } />
<RouteWithLayout layout={EmptyLayout} path='/video' component={VideoPlayer} />
<RouteWithLayout layout={Layout} path='/images' component={Dashboard} />
</div>;


function RouteWithLayout({layout, component, ...rest}){
function RouteWithLayout({ layout, component, ...rest }) {
return (
<Route {...rest} render={(props) =>
React.createElement( layout, props, React.createElement(component, props))
<Route {...rest} render={(props) =>
React.createElement(layout, props, React.createElement(component, props))
}/>
);
}
16 changes: 16 additions & 0 deletions dev/demo-app/webapp/ClientApp/services/appMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
declare var window: any;

const demoModeLocalStorageKey = 'demoMode';

export function isDemoMode() {
return window.localStorage.getItem(demoModeLocalStorageKey) === modes.ENABLED;
}

export function setMode(newMode: modes) {
window.localStorage.setItem(demoModeLocalStorageKey, newMode);
}

export enum modes {
ENABLED = 'enabled',
DISABLED = 'disabled'
}
Loading