Skip to content

Commit

Permalink
added export to google calendar
Browse files Browse the repository at this point in the history
  • Loading branch information
Le0Michine committed Feb 14, 2017
1 parent f9e80a0 commit 615e2d1
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 44 deletions.
7 changes: 7 additions & 0 deletions src/app.common/actions/DisplaySettingsActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,11 @@ export function changeShowTimezoneIdSetting(showTZId: boolean): Action<boolean>
type: "DISPLAY_SETTINGS/SHOW_TIMEZONE_ID",
payload: showTZId
};
}

export function changeShowControlPanelSetting(ShowControlPanel: boolean): Action<boolean> {
return {
type: "DISPLAY_SETTINGS/SHOW_SHOW_CONTROL_PANEL",
payload: ShowControlPanel
};
}
62 changes: 45 additions & 17 deletions src/app.common/models/CalendarEvent.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,70 @@
import * as moment from "moment";
import "moment-timezone";

import { TimeSpanInfo } from "./TimeSpanInfo";
import { TimeSpanInfo, TimeZoneInfo } from "./";

export class CalendarEvent {
static exportToICS(timeSpan: TimeSpanInfo, location: string) {
function timeSpanToTime(timeSpan: TimeSpanInfo) {
const startTime = moment().hours(timeSpan.startHour).minutes(timeSpan.startMinute).seconds(0);
const endTime = moment().hours(timeSpan.endHour).minutes(timeSpan.endMinute).seconds(0);
const mail = "me@gmail.com";
console.log(timeSpan, startTime.toISOString(), endTime.toISOString(), location);
return {startTime, endTime};
}

function getEventDescription(timeSpan: TimeSpanInfo, timelines: TimeZoneInfo[], newLine: string = "\n") {
const {startTime, endTime} = timeSpanToTime(timeSpan);
const footer = `${newLine}${newLine}${newLine}Scheduled with worldtime extension${newLine}`;
return timelines.map((tl: TimeZoneInfo) =>
// `\n${tl.name}, ${tl.timeZoneId.replace("/", ", ").replace("_", " ")}\n` +
`${newLine}${tl.name}${newLine}` +
`${startTime.tz(tl.timeZoneId).format("h:mma\tddd, MMM D YYYY")}${newLine}` +
`${endTime.tz(tl.timeZoneId).format("h:mma\tddd, MMM D YYYY")}`
).concat(footer).join(`${newLine}`);
}

export class CalendarEvent {
static exportToICS(timeSpan: TimeSpanInfo, location: string, timelines: TimeZoneInfo[]) {
const {startTime, endTime} = timeSpanToTime(timeSpan);
const description = getEventDescription(timeSpan, timelines, "\\n");
const formatString = "YYYYMMDDTHHmmss[Z]";
const mail = "me@gmail.com";
const icsMSG =
`BEGIN:VCALENDAR\n` +
`VERSION:2.0\n` +
`PRODID:-//Worldtime//NONSGML v1.0//EN\n` +
`BEGIN:VEVENT\n` +
`UID:${mail}\n` +
// `DTSTAMP:${moment().toISOString()}\n` +
`DESCRIPTION:${description}\n` +
`UID:worldtime\n` +
`DTSTART:${startTime.utc().format(formatString)}\n` +
`DTSTAMP:${moment().utc().format(formatString)}\n` +
`DTEND:${endTime.utc().format(formatString)}\n` +
// `ATTENDEE;CN=My Self ;RSVP=TRUE:MAILTO:${mail}\n` +
// `ORGANIZER;CN=Me:MAILTO::${mail}\n` +
// `DTSTART:${startTime.toISOString()}\n` +
`DTSTART:${startTime.utc().format(formatString)}\n` +
// `DTSTART:${"20170214T123000Z"}\n` +
// `DTEND:${endTime.toISOString()}\n` +
`DTEND:${endTime.utc().format(formatString)}\n` +
// `DTEND:${"20170214T153000Z"}\n` +
`LOCATION:${location}\n` +
`SUMMARY:Our Meeting Office\n` +
`SUMMARY:Let's Meet\n` +
`END:VEVENT\n` +
`END:VCALENDAR`;

window.open(`data:text/calendar;charset=utf8,${encodeURI(icsMSG)}`);
window.open(`data:text/calendar;charset=utf8,${encodeURI(icsMSG)}`);
}

static copyToClipboard(timeSpan: TimeSpanInfo, location: string) {
static getGoogleCalendarLink(timeSpan: TimeSpanInfo, location: string, timelines: TimeZoneInfo[]) {
const {startTime, endTime} = timeSpanToTime(timeSpan);
const description = getEventDescription(timeSpan, timelines);
const formatString = "YYYYMMDDTHHmmss[Z]";
const link = `http://www.google.com/calendar/event?action=TEMPLATE` +
`&text=${"Let's Meet"}` +
`&dates=${startTime.utc().format(formatString)}/${endTime.utc().format(formatString)}` +
`&details=${description}` +
`&location=${location}` +
`&trp=true`;
window.open(encodeURI(link));
}

static copyToClipboard(timeSpan: TimeSpanInfo, location: string, timelines: TimeZoneInfo[]) {
const {startTime, endTime} = timeSpanToTime(timeSpan);
const sceduleData = getEventDescription(timeSpan, timelines);

let copyFrom = document.createElement("textarea");
copyFrom.textContent = "copy content";
copyFrom.textContent = sceduleData;
document.body.appendChild(copyFrom);
copyFrom.focus();
document.execCommand('SelectAll');
Expand Down
1 change: 1 addition & 0 deletions src/app.common/models/DisplaySettingsInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export interface DisplaySettingsInfo {
showDST: DSTSetting;
showUTCOffset: boolean;
showTimeZoneId: boolean;
showControlPanel: boolean;
}

export type DSTSetting = "hide" | "DST" | "Summer/Winter";
4 changes: 4 additions & 0 deletions src/app.common/reducers/DisplaySettingsReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ export const displaySettings = function (state: DisplaySettingsInfo = {} as Disp
const result = Object.assign({}, state, { showTimeZoneId: action.payload });
return result;
}
case "DISPLAY_SETTINGS/SHOW_SHOW_CONTROL_PANEL": {
const result = Object.assign({}, state, { showControlPanel: action.payload });
return result;
}
default:
return state;
}
Expand Down
4 changes: 2 additions & 2 deletions src/app.common/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const initialState = {
createTimeZoneInfo("Asia/Yekaterinburg", "Yekaterinburg")
],
editTimeLineForm: { name: "", timeZoneId: "" } as TimeZoneInfo,
displaySettings: { showDST: "hide", showTimeZoneId: false, showUTCOffset: true },
displaySettings: { showDST: "hide", showTimeZoneId: false, showUTCOffset: true, showControlPanel: true },
selectedTimeSpan: { startHour: 0, startMinute: 0, endHour: 24, endMinute: 0 }
} as AppState;

Expand All @@ -51,7 +51,7 @@ if (process.env.NODE_ENV === "development") {
} else {
enchancer = compose(
persistState("timeLines", { key: "timeLines@0.0.259" }),
persistState("displaySettings", { key: "displaySettings@0.1.265" })
persistState("displaySettings", { key: "displaySettings@0.1.288" })
) as any;
}

Expand Down
16 changes: 12 additions & 4 deletions src/app.options/components/DisplaySettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import { TimeLineControls } from "./TimeLineControls";
import { NavTab } from "./NavTab";
import { DisplaySettingsInfo, TimeZoneInfo, createTimeZoneInfo, getOffset, getHoursWithOffset } from "../../app.common/models";
import { AppState, AppStoreDispatcher } from "../../app.common/store";
import { removeTimeLine, startEdit, swapTimeLines, changeShowDSTSetting, changeShowTimezoneIdSetting, changeShowUTCOffsetSetting } from "../../app.common/actions";
import { removeTimeLine, startEdit, swapTimeLines, changeShowDSTSetting, changeShowTimezoneIdSetting, changeShowUTCOffsetSetting, changeShowControlPanelSetting } from "../../app.common/actions";
// const style = require("./DisplaySettings.css");

interface DisplaySettingsDispatchProps {
changeShowUTCOffsetSetting?: ActionCreator<any>;
changeShowTimezoneIdSetting?: ActionCreator<any>;
changeShowDSTSetting?: ActionCreator<any>;
changeShowControlPanelSetting?: ActionCreator<any>;
}

interface DisplaySettingsStateProps {
Expand All @@ -32,11 +33,12 @@ type DisplaySettingsProps = DisplaySettingsStateProps & DisplaySettingsDispatchP
changeShowDSTSetting: changeShowDSTSetting as ActionCreator<any>,
changeShowTimezoneIdSetting: changeShowTimezoneIdSetting as ActionCreator<any>,
changeShowUTCOffsetSetting: changeShowUTCOffsetSetting as ActionCreator<any>,
changeShowControlPanelSetting: changeShowControlPanelSetting as ActionCreator<any>
}
)
export class DisplaySettings extends React.Component<DisplaySettingsProps, any> {
render() {
const { displaySettings, changeShowUTCOffsetSetting, changeShowTimezoneIdSetting, changeShowDSTSetting } = this.props;
const { displaySettings, changeShowUTCOffsetSetting, changeShowTimezoneIdSetting, changeShowDSTSetting, changeShowControlPanelSetting } = this.props;
return (
<div>
<div className="row">
Expand All @@ -45,7 +47,6 @@ export class DisplaySettings extends React.Component<DisplaySettingsProps, any>
</div>
<div className="col-md-2">
<Checkbox value={displaySettings.showUTCOffset} onChange={(value) => changeShowUTCOffsetSetting(value)} />
{/*<input id="showUTCOffset" type="checkbox" checked={displaySettings.showUTCOffset} onChange={(event) => changeShowUTCOffsetSetting(event.target.checked)} />*/}
</div>
</div>
<div className="row">
Expand All @@ -54,7 +55,14 @@ export class DisplaySettings extends React.Component<DisplaySettingsProps, any>
</div>
<div className="col-md-2">
<Checkbox value={displaySettings.showTimeZoneId} onChange={(value) => changeShowTimezoneIdSetting(value)} />
{/*<input id="showTZId" type="checkbox" checked={displaySettings.showTimeZoneId} onChange={(event) => changeShowTimezoneIdSetting(event.target.checked)} />*/}
</div>
</div>
<div className="row">
<div className="col-md-3">
<label htmlFor="showTZId">Show bottom panel</label>
</div>
<div className="col-md-2">
<Checkbox value={displaySettings.showControlPanel} onChange={(value) => changeShowControlPanelSetting(value)} />
</div>
</div>
<div className="row">
Expand Down
30 changes: 11 additions & 19 deletions src/app/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,35 +60,27 @@ export class Layout extends React.Component<LayoutProps, any> {
<div className={style.timeSpanSelector}>
<Range rangeSize={48} valueMin={valueMin} valueMax={valueMax} onChange={({valueMin, valueMax}) => changeSelectedTimeSpan(valueMin, valueMax)} />
</div>
<div className={style.timeSpanSelector}>
{displaySettings.showControlPanel ? (<div className={style.timeSpanSelector}>
<div className="bottom-panel-container">
<div className="">
<span>{startTime.format("HH:mm")} - {endTime.format("HH:mm")} ({duration.as("hours")})</span>
<span>{startTime.format("HH:mm")} - {endTime.format("HH:mm")} duration: {duration.asHours().toFixed(1)}h</span>
</div>
{/*<div className={style.timeSpanSelectorInput}>
<Input placeholder="hh" />
</div><span> : </span>
<div className={style.timeSpanSelectorInput}>
<Input placeholder="mm" />
</div><span> - </span>
<div className={style.timeSpanSelectorInput}>
<Input placeholder="hh" />
</div><span> : </span>
<div className={style.timeSpanSelectorInput}>
<Input placeholder="mm" />
</div>*/}
<div className="">
<button
className={`btn btn-default btn-material ${ buttonDisabled ? "disabled" : ""}`}
onClick={() => CalendarEvent.copyToClipboard(selectedTimeSpan, timeLines[0].timeZoneId)}
className={`btn btn-default btn-material right-space ${ buttonDisabled ? "disabled" : ""}`}
onClick={() => CalendarEvent.copyToClipboard(selectedTimeSpan, timeLines[0].timeZoneId, timeLines)}
>Copy</button>
<button
className={`btn btn-default btn-material right-space ${ buttonDisabled ? "disabled" : ""}`}
onClick={() => CalendarEvent.getGoogleCalendarLink(selectedTimeSpan, timeLines[0].timeZoneId, timeLines)}
>To Google Cal</button>
<button
className={`btn btn-default btn-material ${ buttonDisabled ? "disabled" : ""}`}
onClick={() => CalendarEvent.exportToICS(selectedTimeSpan, timeLines[0].timeZoneId)}
>Export ot .ics</button>
onClick={() => CalendarEvent.exportToICS(selectedTimeSpan, timeLines[0].timeZoneId, timeLines)}
>Export to .ics</button>
</div>
</div>
</div>
</div>) : null}
</div>
</div>
);
Expand Down
4 changes: 4 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,8 @@ div#app.app-options {
display: flex;
align-items: center;
justify-content: space-between;
}

.right-space {
margin-right: 10px;
}
2 changes: 1 addition & 1 deletion src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<meta charset="utf-8">
<title>Timezone</title>
<link href="bootstrap.min.css" type="text/css" rel="stylesheet"/>
<link href="index.css" type="text/css" rel="stylesheet"/>
<link href="material.css" type="text/css" rel="stylesheet"/>
<link href="index.css" type="text/css" rel="stylesheet"/>
</head>

<body>
Expand Down
2 changes: 1 addition & 1 deletion src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "Worldtime",
"description": "All time zones in one click",
"version": "0.1.284",
"version": "0.1.288",
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"options_page": "options.html",
"browser_action": {
Expand Down

0 comments on commit 615e2d1

Please sign in to comment.