├── .gitignore ├── _config.yml ├── docs ├── _config.yml └── index.html ├── .npmignore ├── jest.config.js ├── src ├── lib │ ├── enums.js │ ├── index.jsx │ ├── utils.js │ └── utils.test.js └── docs │ ├── styles.css │ ├── Dropdown.jsx │ ├── Button.jsx │ ├── CodeSnippet.jsx │ ├── Modal.jsx │ ├── index.html │ └── index.jsx ├── .babelrc ├── lib ├── enums.js ├── utils.js └── index.js ├── .travis.yml ├── .github └── ISSUE_TEMPLATE │ ├── 2.Feature_request.md │ └── 1.Bug_report.md ├── webpack.config.js ├── LICENSE ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | coverage 2 | node_modules -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | docs 2 | src 3 | .babelrc 4 | webpack.config.js -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testURL: 'http://localhost/' 3 | }; -------------------------------------------------------------------------------- /src/lib/enums.js: -------------------------------------------------------------------------------- 1 | export const SHARE_SITES = { 2 | GOOGLE: 'Google', 3 | ICAL: 'iCal', 4 | OUTLOOK: 'Outlook', 5 | YAHOO: 'Yahoo', 6 | }; -------------------------------------------------------------------------------- /src/docs/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background: #eee; 7 | font-family: "Tahoma", Arial, sans-serif; 8 | } 9 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/env", "@babel/react"], 3 | "plugins": [ 4 | "@babel/plugin-proposal-object-rest-spread", 5 | "@babel/plugin-proposal-class-properties" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /lib/enums.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.SHARE_SITES = void 0; 7 | var SHARE_SITES = { 8 | GOOGLE: 'Google', 9 | ICAL: 'iCal', 10 | OUTLOOK: 'Outlook', 11 | YAHOO: 'Yahoo' 12 | }; 13 | exports.SHARE_SITES = SHARE_SITES; -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: node_js 4 | node_js: 5 | - 8 6 | 7 | before_install: 8 | - yarn add codecov.io coveralls 9 | 10 | after_success: 11 | - cat ./coverage/lcov.info | ./node_modules/codecov.io/bin/codecov.io.js 12 | - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js 13 | 14 | branches: 15 | only: 16 | - master -------------------------------------------------------------------------------- /src/docs/Dropdown.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { css } from 'emotion'; 3 | 4 | const dropdownStyles = css` 5 | padding: 10px; 6 | border: 1px solid #E5E5E5; 7 | border-top: none; 8 | width: 300px; 9 | background-color: #FFF; 10 | margin: 0 auto; 11 | `; 12 | 13 | export default function Dropdown({ children }) { 14 | return ( 15 |
107 |
108 | This component is expected to work on modern browsers, but if it breaks on a particular browser please [file an issue](https://github.com/jasonleibowitz/react-add-to-calendar-hoc/issues/new?template=1.Bug_report.md). We can check the problem using [browserstack](http://browserstack.com) - a great service for cross-browser testing. They also support open source projects like this one.
109 |
110 | ## License
111 |
112 | MIT
113 |
--------------------------------------------------------------------------------
/src/docs/index.jsx:
--------------------------------------------------------------------------------
1 | import 'core-js/es6';
2 | import 'core-js/es7';
3 |
4 | import React from "react";
5 | import { render } from "react-dom";
6 | import AddToCalendarHOC, { SHARE_SITES } from "../../lib";
7 | import Button from './Button';
8 | import CalendarModal from './Modal';
9 | import CodeSnippet from './CodeSnippet';
10 | import Dropdown from './Dropdown';
11 | import { DateTime } from 'luxon';
12 | import moment from 'moment-timezone';
13 | import { css } from 'emotion';
14 | import "./styles.css";
15 |
16 | const pageStyles = css`
17 | width: 100%;
18 | padding: 0 20px;
19 | margin: 0 auto;
20 |
21 | @media (min-width: 768px) {
22 | width: 75%;
23 | padding: 0;
24 | }
25 | `;
26 |
27 | const componentStyles = css`
28 | width: 100%;
29 | margin: 0 auto;
30 | text-align: center;
31 | padding: 0 0 30px;
32 |
33 | @media (min-width: 768px) {
34 | width: 50%;
35 | }
36 | `;
37 |
38 | const linkStyles = css`
39 | text-decoration: none;
40 | display: block;
41 | color: #E42D2D;
42 | font-size: 18px;
43 | text-align: center;
44 | padding: 6px;
45 | `;
46 |
47 | const titleStyles = css`
48 | margin: 75px 0;
49 | text-align: center;
50 | `;
51 |
52 | const highlightText = css`
53 | font-family: Courier;
54 | font-style: italic;
55 | color: rgb(218, 49, 80);
56 | background-color: #FFF;
57 | padding: 1px 4px;
58 | `;
59 |
60 | const subTitleStyles = css`
61 | margin: 50px 0;
62 | text-align: center;
63 | `;
64 |
65 | const paragraphStyles = css`
66 | margin: 30px auto;
67 | width: 80%;
68 | `;
69 |
70 | const startDatetime = moment().utc().add(2, 'days');
71 | const endDatetime = startDatetime.clone().add(2, 'hours');
72 | const duration = endDatetime.diff(startDatetime, 'hours');
73 | const event = {
74 | description: 'Description of event. Going to have a lot of fun doing things that we scheduled ahead of time.',
75 | duration,
76 | endDatetime: endDatetime.format('YYYYMMDDTHHmmssZ'),
77 | location: 'NYC',
78 | startDatetime: startDatetime.format('YYYYMMDDTHHmmssZ'),
79 | title: 'Super Fun Event',
80 | }
81 |
82 | const eventInDifferentTimezone = {
83 | ...event,
84 | location: 'London',
85 | endDatetime: moment().tz('Europe/London').add(2, 'days').add(2, 'hours').format('YYYYMMDDTHHmmss'),
86 | startDatetime: moment().tz('Europe/London').add(2, 'days').format('YYYYMMDDTHHmmss'),
87 | timezone: 'Europe/London',
88 | }
89 |
90 | const luxonStart = DateTime.fromObject({ year: 2018, month: 10, day: 24, hour: 12, minute: 15, zone: 'America/New_York' });
91 | const luxonEnd = DateTime.fromObject({ year: 2018, month: 10, day: 24, hour: 14, minute: 15, zone: 'America/New_York' });
92 | const luxonEvent = {
93 | ...event,
94 | startDatetime: `${luxonStart.toFormat('yyyyLLdd')}T${luxonStart.toFormat('HHmmss')}`,
95 | endDatetime: `${luxonEnd.toFormat('yyyyLLdd')}T${luxonEnd.toFormat('HHmmss')}`,
96 | location: 'NYC',
97 | timezone: 'America/New_York',
98 | }
99 |
100 | const AddToCalendarDropdown = AddToCalendarHOC(Button, Dropdown);
101 | const AddToCalendarModal = AddToCalendarHOC(Button, CalendarModal);
102 | const isiOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
103 |
104 | function Demo() {
105 | return (
106 | iPhones don't allow users to select which app they want to open ics files with, so there is no reason to offer both iCal and Outlook options for users on iOS devices. This example shows how to conditionally change which items to display based on the user's device.
271 |To support events in a specific timezone you have to do a couple of things. First, pass in an additional property, timezone. The value of this should be a valid TZ environment variable (See here for a list).
297 |You should also pass the value of startDatetime and endDatetime as local values and not UTC. In other words, if you want to create an event at 11am EST you should pass in a time value of 11am, not 7am UTC (EST has -04:00 offset). You can do this by formatting the date as YYYYMMDDTHHmmss - without the Z property.
298 |Doing this will result in two things -- regardless of the timezone of your users, the event will always be created at the correct time for the timezone set. Secondly, the event will now include timezone information, i.e. it will say Eastern Time.
299 |Moment is known to be a MASSIVE library. v2.22.2 is 64.2kb minified + gzipped and moment-timezone v0.5.21 is 89.8kb minified + gzipped. There are plenty of other date time libraries for JS that are way smaller. Using one of these helps you avoid overly bloating your application and sending too many vendor files to the client. One great option is Luxon. Luxon v.1.4.4 is 16.9kb minified + gzipped.
329 |This example shows how to use the Luxon library (instead of Moment) to construct startDatetime and endDatetime
330 |