├── .npmignore ├── .eslintignore ├── src ├── demo │ ├── github_logo.png │ ├── index.js │ ├── index.css │ └── App.js └── lib │ ├── translations │ ├── index.js │ ├── english.js │ └── german.js │ ├── utils │ ├── computeRRule │ │ ├── toString │ │ └── fromString │ │ │ ├── computeStartOnDate.js │ │ │ ├── computeEndOnDate.js │ │ │ ├── computeWeekStartDay.js │ │ │ ├── computeEndAfter.js │ │ │ ├── computeDailyInterval.js │ │ │ ├── computeHourlyInterval.js │ │ │ ├── computeMonthlyInterval.js │ │ │ ├── computeWeeklyInterval.js │ │ │ ├── computeEndMode.js │ │ │ ├── computeMonthlyMode.js │ │ │ ├── computeYearlyMode.js │ │ │ ├── computeMonthlyOnDay.js │ │ │ ├── computeYearlyOnMonthday.js │ │ │ ├── computeYearlyOnMonth.js │ │ │ ├── computeYearlyOnTheMonth.js │ │ │ ├── computeFrequency.js │ │ │ ├── computeWeeklyDays.js │ │ │ ├── computeYearlyOnTheWhich.js │ │ │ ├── computeMonthlyOnTheWhich.js │ │ │ ├── computeMonthlyOnTheDay.js │ │ │ ├── computeYearlyOnTheMonthday.js │ │ │ └── computeRRule.js │ ├── numericalFieldHandler.js │ ├── translateLabel.js │ └── configureInitialState.js │ ├── styles │ ├── index.css │ └── react-datetime.css │ ├── index.js │ ├── constants │ └── index.js │ └── components │ ├── Start │ ├── index.js │ └── OnDate.js │ ├── End │ ├── After.js │ ├── OnDate.js │ └── index.js │ ├── Repeat │ ├── Daily │ │ └── index.js │ ├── Hourly │ │ └── index.js │ ├── Yearly │ │ ├── index.js │ │ ├── On.js │ │ └── OnThe.js │ ├── Monthly │ │ ├── On.js │ │ ├── index.js │ │ └── OnThe.js │ ├── Weekly │ │ └── index.js │ └── index.js │ └── ReactRRuleGenerator.js ├── .babelrc ├── config ├── jest │ ├── fileTransform.js │ └── cssTransform.js ├── polyfills.js ├── paths.js ├── env.js ├── webpackDevServer.config.js ├── webpack.config.prod.js ├── webpack.config.dev.js └── webpack.config.prod.demo.js ├── .gitignore ├── .eslintrc ├── public └── index.html ├── scripts ├── test.js ├── start.js ├── build.js └── build-demo.js ├── LICENSE ├── package.json └── README.md /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /src/demo/registerServiceWorker.js 2 | -------------------------------------------------------------------------------- /src/demo/github_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teq/react-rrule-generator/master/src/demo/github_logo.png -------------------------------------------------------------------------------- /src/lib/translations/index.js: -------------------------------------------------------------------------------- 1 | import english from './english'; 2 | import german from './german'; 3 | 4 | export default { english, german }; 5 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react", "es2015"], 3 | "plugins": [ 4 | "transform-class-properties", 5 | "transform-object-rest-spread" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/toString/computeMonthlyOn.js: -------------------------------------------------------------------------------- 1 | const computeMonthlyOn = on => ({ 2 | bymonthday: on.day, 3 | }); 4 | 5 | export default computeMonthlyOn; 6 | -------------------------------------------------------------------------------- /src/demo/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | ReactDOM.render(, document.getElementById('root')); 6 | -------------------------------------------------------------------------------- /src/lib/styles/index.css: -------------------------------------------------------------------------------- 1 | @import 'react-datetime.css'; 2 | 3 | .rdt .form-control { 4 | background-color: white; 5 | } 6 | 7 | .opacity-50 { 8 | opacity: 0.5; 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/index.js: -------------------------------------------------------------------------------- 1 | import ReactRRuleGenerator from './components/ReactRRuleGenerator'; 2 | import translations from './translations'; 3 | 4 | export default ReactRRuleGenerator; 5 | export { translations }; 6 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/toString/computeDaily.js: -------------------------------------------------------------------------------- 1 | import RRule from 'rrule'; 2 | 3 | const computeDaily = ({ interval }) => ({ 4 | freq: RRule.DAILY, 5 | interval, 6 | }); 7 | 8 | export default computeDaily; 9 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/toString/computeHourly.js: -------------------------------------------------------------------------------- 1 | import RRule from 'rrule'; 2 | 3 | const computeHourly = ({ interval }) => ({ 4 | freq: RRule.HOURLY, 5 | interval, 6 | }); 7 | 8 | export default computeHourly; 9 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeStartOnDate.js: -------------------------------------------------------------------------------- 1 | const computeStartOnDate = (data, rruleObj) => { 2 | if (!rruleObj.dtstart) { 3 | return data.start.onDate.date; 4 | } 5 | 6 | return rruleObj.dtstart; 7 | }; 8 | export default computeStartOnDate; 9 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/toString/computeYearlyOn.js: -------------------------------------------------------------------------------- 1 | import { MONTHS } from '../../../constants/index'; 2 | 3 | const computeYearlyOn = on => ({ 4 | bymonth: MONTHS.indexOf(on.month) + 1, 5 | bymonthday: on.day, 6 | }); 7 | 8 | export default computeYearlyOn; 9 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeEndOnDate.js: -------------------------------------------------------------------------------- 1 | const computeEndOnDate = (data, rruleObj) => { 2 | if (!rruleObj.until) { 3 | return data.end.onDate.date; 4 | } 5 | 6 | return rruleObj.until; 7 | }; 8 | 9 | export default computeEndOnDate; 10 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeWeekStartDay.js: -------------------------------------------------------------------------------- 1 | const computeWeekStartDay = (data, rruleObj) => { 2 | if (!rruleObj.wkst) { 3 | return data.options.weekStartsOnSunday; 4 | } 5 | return rruleObj.wkst === 6; 6 | }; 7 | 8 | export default computeWeekStartDay; 9 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeEndAfter.js: -------------------------------------------------------------------------------- 1 | const computeEndAfter = (data, rruleObj) => { 2 | if (!rruleObj.count && rruleObj.count !== 0) { 3 | return data.end.after; 4 | } 5 | 6 | return rruleObj.count; 7 | }; 8 | 9 | export default computeEndAfter; 10 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeDailyInterval.js: -------------------------------------------------------------------------------- 1 | const computeDailyInterval = (data, rruleObj) => { 2 | if (rruleObj.freq !== 3) { 3 | return data.repeat.daily.interval; 4 | } 5 | 6 | return rruleObj.interval; 7 | }; 8 | 9 | export default computeDailyInterval; 10 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeHourlyInterval.js: -------------------------------------------------------------------------------- 1 | const computeHourlyInterval = (data, rruleObj) => { 2 | if (rruleObj.freq !== 4) { 3 | return data.repeat.daily.interval; 4 | } 5 | 6 | return rruleObj.interval; 7 | }; 8 | 9 | export default computeHourlyInterval; 10 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeMonthlyInterval.js: -------------------------------------------------------------------------------- 1 | const computeMonthlyInterval = (data, rruleObj) => { 2 | if (rruleObj.freq !== 1) { 3 | return data.repeat.monthly.interval; 4 | } 5 | 6 | return rruleObj.interval; 7 | }; 8 | 9 | export default computeMonthlyInterval; 10 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeWeeklyInterval.js: -------------------------------------------------------------------------------- 1 | const computeWeeklyInterval = (data, rruleObj) => { 2 | if (rruleObj.freq !== 2) { 3 | return data.repeat.weekly.interval; 4 | } 5 | 6 | return rruleObj.interval; 7 | }; 8 | 9 | export default computeWeeklyInterval; 10 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeEndMode.js: -------------------------------------------------------------------------------- 1 | const computeEndMode = (data, rruleObj) => { 2 | if (rruleObj.count || rruleObj.count === 0) { 3 | return 'After'; 4 | } 5 | 6 | if (rruleObj.until) { 7 | return 'On date'; 8 | } 9 | 10 | return 'Never'; 11 | }; 12 | 13 | export default computeEndMode; 14 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeMonthlyMode.js: -------------------------------------------------------------------------------- 1 | const computeMonthlyMode = (data, rruleObj) => { 2 | if (rruleObj.freq !== 1) { 3 | return data.repeat.monthly.mode; 4 | } 5 | 6 | if (rruleObj.bymonthday) { 7 | return 'on'; 8 | } 9 | 10 | return 'on the'; 11 | }; 12 | 13 | export default computeMonthlyMode; 14 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeYearlyMode.js: -------------------------------------------------------------------------------- 1 | const computeYearlyMode = (data, rruleObj) => { 2 | if (rruleObj.freq !== 0 || !rruleObj.bymonth) { 3 | return data.repeat.yearly.mode; 4 | } 5 | 6 | if (rruleObj.bymonthday) { 7 | return 'on'; 8 | } 9 | 10 | return 'on the'; 11 | }; 12 | 13 | export default computeYearlyMode; 14 | -------------------------------------------------------------------------------- /config/jest/fileTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | 5 | // This is a custom Jest transformer turning file imports into filenames. 6 | // http://facebook.github.io/jest/docs/tutorial-webpack.html 7 | 8 | module.exports = { 9 | process(src, filename) { 10 | return `module.exports = ${JSON.stringify(path.basename(filename))};`; 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # misc 10 | .DS_Store 11 | .env.local 12 | .env.development.local 13 | .env.test.local 14 | .env.production.local 15 | 16 | npm-debug.log* 17 | yarn-debug.log* 18 | yarn-error.log* 19 | 20 | .idea/ 21 | /build/ 22 | /build-demo/ 23 | -------------------------------------------------------------------------------- /config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // This is a custom Jest transformer turning style imports into empty objects. 4 | // http://facebook.github.io/jest/docs/tutorial-webpack.html 5 | 6 | module.exports = { 7 | process() { 8 | return 'module.exports = {};'; 9 | }, 10 | getCacheKey() { 11 | // The output is always the same. 12 | return 'cssTransform'; 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/toString/computeEnd.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment'; 2 | 3 | const computeEnd = ({ mode, after, onDate: { date } }) => { 4 | const end = {}; 5 | 6 | if (mode === 'After') { 7 | end.count = after; 8 | } 9 | 10 | if (mode === 'On date') { 11 | end.until = moment(date).format(); 12 | } 13 | 14 | return end; 15 | }; 16 | 17 | export default computeEnd; 18 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/toString/computeOptions.js: -------------------------------------------------------------------------------- 1 | import RRule from 'rrule'; 2 | 3 | const computeOptions = ({ hideStart, weekStartsOnSunday }) => { 4 | const options = {}; 5 | 6 | if (hideStart) { 7 | options.dtstart = null; 8 | } 9 | 10 | if (weekStartsOnSunday) { 11 | options.wkst = RRule.SU; 12 | } 13 | 14 | return options; 15 | }; 16 | 17 | export default computeOptions; 18 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/toString/computeYearly.js: -------------------------------------------------------------------------------- 1 | import RRule from 'rrule'; 2 | 3 | import computeYearlyOn from './computeYearlyOn'; 4 | import computeYearlyOnThe from './computeYearlyOnThe'; 5 | 6 | const computeYearly = ({ mode, on, onThe }) => ({ 7 | freq: RRule.YEARLY, 8 | ...(mode === 'on' ? computeYearlyOn(on) : computeYearlyOnThe(onThe)), 9 | }); 10 | 11 | export default computeYearly; 12 | 13 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeMonthlyOnDay.js: -------------------------------------------------------------------------------- 1 | const computeMonthlyOnDay = (data, rruleObj) => { 2 | if (rruleObj.freq !== 1 || !rruleObj.bymonthday) { 3 | return data.repeat.monthly.on.day; 4 | } 5 | 6 | if (typeof rruleObj.bymonthday === 'number') { 7 | return rruleObj.bymonthday 8 | } 9 | 10 | return rruleObj.bymonthday[0]; 11 | }; 12 | 13 | export default computeMonthlyOnDay; 14 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeYearlyOnMonthday.js: -------------------------------------------------------------------------------- 1 | const computeYearlyOnMonthday = (data, rruleObj) => { 2 | if (rruleObj.freq !== 0 || !rruleObj.bymonthday) { 3 | return data.repeat.yearly.on.day; 4 | } 5 | 6 | if (typeof rruleObj.bymonthday === 'number') { 7 | return rruleObj.bymonthday 8 | } 9 | 10 | return rruleObj.bymonthday[0]; 11 | }; 12 | 13 | export default computeYearlyOnMonthday; 14 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/toString/computeWeekly.js: -------------------------------------------------------------------------------- 1 | import RRule from 'rrule'; 2 | import { values } from 'lodash'; 3 | 4 | const computeWeekly = ({ interval, days }) => ({ 5 | freq: RRule.WEEKLY, 6 | interval, 7 | byweekday: values(days).reduce( 8 | (activeDays, isDayActive, dayIndex) => 9 | (isDayActive ? [...activeDays, dayIndex] : activeDays), 10 | [], 11 | ), 12 | }); 13 | 14 | export default computeWeekly; 15 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "standard", 5 | "standard-react", 6 | "airbnb" 7 | ], 8 | "plugins": [ 9 | "react" 10 | ], 11 | "rules": { 12 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 13 | "no-trailing-spaces": ["error", { "skipBlankLines": true }], 14 | "max-len": [2, 120, 2], 15 | "import/no-extraneous-dependencies": 0 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React RRule Generator 8 | 9 | 10 | 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/toString/computeMonthly.js: -------------------------------------------------------------------------------- 1 | import RRule from 'rrule'; 2 | 3 | import computeMonthlyOn from './computeMonthlyOn'; 4 | import computeMonthlyOnThe from './computeMonthlyOnThe'; 5 | 6 | const computeMonthly = ({ 7 | mode, 8 | interval, 9 | on, 10 | onThe, 11 | }) => ({ 12 | freq: RRule.MONTHLY, 13 | interval, 14 | ...(mode === 'on' ? computeMonthlyOn(on) : computeMonthlyOnThe(onThe)), 15 | }); 16 | 17 | export default computeMonthly; 18 | -------------------------------------------------------------------------------- /src/lib/constants/index.js: -------------------------------------------------------------------------------- 1 | export const DATE_TIME_FORMAT = 'YYYY-MM-DD'; 2 | 3 | export const MONTHS = [ 4 | 'Jan', 5 | 'Feb', 6 | 'Mar', 7 | 'Apr', 8 | 'May', 9 | 'Jun', 10 | 'Jul', 11 | 'Aug', 12 | 'Sep', 13 | 'Oct', 14 | 'Nov', 15 | 'Dec' 16 | ]; 17 | export const DAYS = [ 18 | 'Monday', 19 | 'Tuesday', 20 | 'Wednesday', 21 | 'Thursday', 22 | 'Friday', 23 | 'Saturday', 24 | 'Sunday', 25 | 'Day', 26 | 'Weekday', 27 | 'Weekend day' 28 | ]; 29 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeYearlyOnMonth.js: -------------------------------------------------------------------------------- 1 | import { MONTHS } from '../../../constants/index'; 2 | 3 | const computeYearlyOnMonth = (data, rruleObj) => { 4 | if (rruleObj.freq !== 0 || !rruleObj.bymonthday) { 5 | return data.repeat.yearly.on.month; 6 | } 7 | 8 | if (typeof rruleObj.bymonth === 'number') { 9 | return MONTHS[rruleObj.bymonth - 1] 10 | } 11 | 12 | return MONTHS[rruleObj.bymonth[0] - 1]; 13 | }; 14 | 15 | export default computeYearlyOnMonth; 16 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeYearlyOnTheMonth.js: -------------------------------------------------------------------------------- 1 | import { MONTHS } from '../../../constants/index'; 2 | 3 | const computeYearlyOnTheMonth = (data, rruleObj) => { 4 | if (rruleObj.freq !== 0 || !rruleObj.byweekday) { 5 | return data.repeat.yearly.onThe.month; 6 | } 7 | 8 | if (typeof rruleObj.bymonth === 'number') { 9 | return MONTHS[rruleObj.bymonth - 1] 10 | } 11 | 12 | return MONTHS[rruleObj.bymonth[0] - 1]; 13 | }; 14 | 15 | export default computeYearlyOnTheMonth; 16 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/toString/computeStart.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment'; 2 | 3 | const computeStart = ({ onDate: { date } }) => { 4 | // verify that incoming date is valid 5 | // by seeing if it can be converted into a moment object. 6 | // if not, then create a new date 7 | if (!moment.isMoment(moment(date))) { 8 | date = new Date().setMilliseconds(0); 9 | } 10 | 11 | return { 12 | dtstart: moment(date).toDate(), 13 | }; 14 | }; 15 | 16 | export default computeStart; 17 | -------------------------------------------------------------------------------- /src/lib/utils/numericalFieldHandler.js: -------------------------------------------------------------------------------- 1 | import { isNaN } from 'lodash'; 2 | 3 | const numericalFieldHandler = callback => (event) => { 4 | // Convert input from a string to a number 5 | const inputNumber = +event.target.value; 6 | // Check if is a number and is less than 1000 7 | if (isNaN(inputNumber) || inputNumber >= 1000) return; 8 | 9 | const editedEvent = { target: { value: inputNumber, name: event.target.name } }; 10 | callback(editedEvent); 11 | }; 12 | 13 | export default numericalFieldHandler; 14 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeFrequency.js: -------------------------------------------------------------------------------- 1 | const computeFrequency = (data, rruleObj) => { 2 | switch (rruleObj.freq) { 3 | case 0: { 4 | return 'Yearly'; 5 | } 6 | case 1: { 7 | return 'Monthly'; 8 | } 9 | case 2: { 10 | return 'Weekly'; 11 | } 12 | case 3: { 13 | return 'Daily'; 14 | } 15 | case 4: { 16 | return 'Hourly'; 17 | } 18 | default: { 19 | return data.repeat.frequency; 20 | } 21 | } 22 | }; 23 | 24 | export default computeFrequency; 25 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeWeeklyDays.js: -------------------------------------------------------------------------------- 1 | const computeWeeklyDays = (data, rruleObj) => { 2 | let weekdays = []; 3 | 4 | if (rruleObj.freq !== 2) { 5 | return data.repeat.weekly.days; 6 | } 7 | 8 | if (rruleObj.byweekday) { 9 | weekdays = rruleObj.byweekday.map(weekday => weekday.weekday); 10 | } 11 | 12 | return { 13 | mon: weekdays.includes(0), 14 | tue: weekdays.includes(1), 15 | wed: weekdays.includes(2), 16 | thu: weekdays.includes(3), 17 | fri: weekdays.includes(4), 18 | sat: weekdays.includes(5), 19 | sun: weekdays.includes(6), 20 | }; 21 | }; 22 | 23 | export default computeWeeklyDays; 24 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/toString/computeRRule.js: -------------------------------------------------------------------------------- 1 | import RRule from 'rrule'; 2 | 3 | import computeStart from './computeStart'; 4 | import computeRepeat from './computeRepeat'; 5 | import computeEnd from './computeEnd'; 6 | import computeOptions from './computeOptions'; 7 | 8 | const computeRRule = ({ 9 | start, 10 | repeat, 11 | end, 12 | options, 13 | }) => { 14 | const rruleObject = { 15 | ...computeStart(start), 16 | ...computeRepeat(repeat), 17 | ...computeEnd(end), 18 | ...computeOptions(options), 19 | }; 20 | const rrule = new RRule(rruleObject); 21 | return rrule.toString(); 22 | }; 23 | 24 | export default computeRRule; 25 | -------------------------------------------------------------------------------- /config/polyfills.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (typeof Promise === 'undefined') { 4 | // Rejection tracking prevents a common issue where React gets into an 5 | // inconsistent state due to an error, but it gets swallowed by a Promise, 6 | // and the user has no idea what causes React's erratic future behavior. 7 | require('promise/lib/rejection-tracking').enable(); 8 | window.Promise = require('promise/lib/es6-extensions.js'); 9 | } 10 | 11 | // fetch() polyfill for making API calls. 12 | require('whatwg-fetch'); 13 | 14 | // Object.assign() is commonly used with React. 15 | // It will use the native implementation if it's present and isn't buggy. 16 | Object.assign = require('object-assign'); 17 | -------------------------------------------------------------------------------- /src/lib/utils/translateLabel.js: -------------------------------------------------------------------------------- 1 | import { each, isFunction, isPlainObject, get } from 'lodash'; 2 | 3 | const replacePlaceholder = (text, replacements = {}) => { 4 | each(replacements, (value, key) => { 5 | text = text.replace(`%{${key}}`, value); 6 | }); 7 | 8 | return text; 9 | }; 10 | 11 | const translateLabel = (translations, key, replacements = {}) => { 12 | if (isFunction(translations)) { 13 | return translations(key, replacements); 14 | } else if (isPlainObject(translations)) { 15 | return replacePlaceholder( 16 | get(translations, key, `[translation missing '${key}']`), 17 | replacements, 18 | ); 19 | } 20 | 21 | return null; 22 | }; 23 | 24 | export default translateLabel; 25 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeYearlyOnTheWhich.js: -------------------------------------------------------------------------------- 1 | const computeYearlyOnTheWhich = (data, rruleObj) => { 2 | if (rruleObj.freq !== 0 || !rruleObj.byweekday) { 3 | return data.repeat.yearly.onThe.which; 4 | } 5 | 6 | const bysetpos = (typeof rruleObj.bysetpos === 'number') ? rruleObj.bysetpos : rruleObj.bysetpos[0]; 7 | 8 | switch (bysetpos) { 9 | case 1: { 10 | return 'First'; 11 | } 12 | case 2: { 13 | return 'Second'; 14 | } 15 | case 3: { 16 | return 'Third'; 17 | } 18 | case 4: { 19 | return 'Fourth'; 20 | } 21 | case -1: { 22 | return 'Last'; 23 | } 24 | default: { 25 | return data.repeat.yearly.onThe.which; 26 | } 27 | } 28 | }; 29 | 30 | export default computeYearlyOnTheWhich; 31 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeMonthlyOnTheWhich.js: -------------------------------------------------------------------------------- 1 | const computeMonthlyOnTheWhich = (data, rruleObj) => { 2 | if (rruleObj.freq !== 1 || !rruleObj.bysetpos) { 3 | return data.repeat.monthly.onThe.which; 4 | } 5 | 6 | const bysetpos = (typeof rruleObj.bysetpos === 'number') ? rruleObj.bysetpos : rruleObj.bysetpos[0]; 7 | 8 | switch (bysetpos) { 9 | case 1: { 10 | return 'First'; 11 | } 12 | case 2: { 13 | return 'Second'; 14 | } 15 | case 3: { 16 | return 'Third'; 17 | } 18 | case 4: { 19 | return 'Fourth'; 20 | } 21 | case -1: { 22 | return 'Last'; 23 | } 24 | default: { 25 | return data.repeat.monthly.onThe.which; 26 | } 27 | } 28 | }; 29 | 30 | export default computeMonthlyOnTheWhich; 31 | -------------------------------------------------------------------------------- /scripts/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Do this as the first thing so that any code reading it knows the right env. 4 | process.env.BABEL_ENV = 'test'; 5 | process.env.NODE_ENV = 'test'; 6 | process.env.PUBLIC_URL = ''; 7 | 8 | // Makes the script crash on unhandled rejections instead of silently 9 | // ignoring them. In the future, promise rejections that are not handled will 10 | // terminate the Node.js process with a non-zero exit code. 11 | process.on('unhandledRejection', err => { 12 | throw err; 13 | }); 14 | 15 | // Ensure environment variables are read. 16 | require('../config/env'); 17 | 18 | const jest = require('jest'); 19 | const argv = process.argv.slice(2); 20 | 21 | // Watch unless on CI or in coverage mode 22 | if (!process.env.CI && argv.indexOf('--coverage') < 0) { 23 | argv.push('--watch'); 24 | } 25 | 26 | 27 | jest.run(argv); 28 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/toString/computeRepeat.js: -------------------------------------------------------------------------------- 1 | import computeYearly from './computeYearly'; 2 | import computeMonthly from './computeMonthly'; 3 | import computeWeekly from './computeWeekly'; 4 | import computeDaily from './computeDaily'; 5 | import computeHourly from './computeHourly'; 6 | 7 | const computeRepeat = ({ 8 | frequency, 9 | yearly, 10 | monthly, 11 | weekly, 12 | daily, 13 | hourly, 14 | }) => { 15 | switch (frequency) { 16 | case 'Yearly': { 17 | return computeYearly(yearly); 18 | } 19 | case 'Monthly': { 20 | return computeMonthly(monthly); 21 | } 22 | case 'Weekly': { 23 | return computeWeekly(weekly); 24 | } 25 | case 'Daily': { 26 | return computeDaily(daily); 27 | } 28 | case 'Hourly': { 29 | return computeHourly(hourly); 30 | } 31 | default: 32 | return {}; 33 | } 34 | }; 35 | 36 | export default computeRepeat; 37 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeMonthlyOnTheDay.js: -------------------------------------------------------------------------------- 1 | const computeMonthlyOnTheDay = (data, rruleObj) => { 2 | if (rruleObj.freq !== 1 || !rruleObj.byweekday) { 3 | return data.repeat.monthly.onThe.day; 4 | } 5 | 6 | const weekdays = rruleObj.byweekday.map(weekday => weekday.weekday).join(','); 7 | 8 | switch (weekdays) { 9 | case '0': { 10 | return 'Monday'; 11 | } 12 | case '1': { 13 | return 'Tuesday'; 14 | } 15 | case '2': { 16 | return 'Wednesday'; 17 | } 18 | case '3': { 19 | return 'Thursday'; 20 | } 21 | case '4': { 22 | return 'Friday'; 23 | } 24 | case '5': { 25 | return 'Saturday'; 26 | } 27 | case '6': { 28 | return 'Sunday'; 29 | } 30 | case '0,1,2,3,4,5,6': { 31 | return 'Day'; 32 | } 33 | case '0,1,2,3,4': { 34 | return 'Weekday'; 35 | } 36 | case '5,6': { 37 | return 'Weekend day'; 38 | } 39 | default: { 40 | return data.repeat.monthly.onThe.day; 41 | } 42 | } 43 | }; 44 | 45 | export default computeMonthlyOnTheDay; 46 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/fromString/computeYearlyOnTheMonthday.js: -------------------------------------------------------------------------------- 1 | const computeYearlyOnTheMonthday = (data, rruleObj) => { 2 | if (rruleObj.freq !== 0 || !rruleObj.byweekday) { 3 | return data.repeat.yearly.onThe.day; 4 | } 5 | 6 | const weekdays = rruleObj.byweekday.map(weekday => weekday.weekday).join(','); 7 | 8 | switch (weekdays) { 9 | case '0': { 10 | return 'Monday'; 11 | } 12 | case '1': { 13 | return 'Tuesday'; 14 | } 15 | case '2': { 16 | return 'Wednesday'; 17 | } 18 | case '3': { 19 | return 'Thursday'; 20 | } 21 | case '4': { 22 | return 'Friday'; 23 | } 24 | case '5': { 25 | return 'Saturday'; 26 | } 27 | case '6': { 28 | return 'Sunday'; 29 | } 30 | case '0,1,2,3,4,5,6': { 31 | return 'Day'; 32 | } 33 | case '0,1,2,3,4': { 34 | return 'Weekday'; 35 | } 36 | case '5,6': { 37 | return 'Weekend day'; 38 | } 39 | default: { 40 | return data.repeat.yearly.onThe.day; 41 | } 42 | } 43 | }; 44 | 45 | export default computeYearlyOnTheMonthday; 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Filip Duczyminski 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/lib/components/Start/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import StartOnDate from './OnDate'; 4 | 5 | import translateLabel from '../../utils/translateLabel'; 6 | 7 | const Start = ({ 8 | id, 9 | start: { 10 | onDate, 11 | }, 12 | handleChange, 13 | translations 14 | }) => ( 15 |
16 |
17 |
18 | 26 |
27 | 28 |
29 |
30 | ); 31 | 32 | Start.propTypes = { 33 | id: PropTypes.string.isRequired, 34 | start: PropTypes.shape({ 35 | onDate: PropTypes.object.isRequired, 36 | }).isRequired, 37 | handleChange: PropTypes.func.isRequired, 38 | translations: PropTypes.oneOfType([PropTypes.object, PropTypes.func]).isRequired, 39 | }; 40 | 41 | export default Start; 42 | -------------------------------------------------------------------------------- /src/lib/components/End/After.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import numericalFieldHandler from '../../utils/numericalFieldHandler'; 4 | import translateLabel from '../../utils/translateLabel'; 5 | 6 | const EndAfter = ({ 7 | id, 8 | after, 9 | handleChange, 10 | translations 11 | }) => ( 12 |
13 |
14 |
15 | 23 |
24 |
25 | {translateLabel(translations, 'end.executions')} 26 |
27 |
28 |
29 | ); 30 | 31 | EndAfter.propTypes = { 32 | id: PropTypes.string.isRequired, 33 | after: PropTypes.number.isRequired, 34 | handleChange: PropTypes.func.isRequired, 35 | translations: PropTypes.oneOfType([PropTypes.object, PropTypes.func]).isRequired, 36 | }; 37 | 38 | export default EndAfter; 39 | -------------------------------------------------------------------------------- /src/lib/components/Repeat/Daily/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import numericalFieldHandler from '../../../utils/numericalFieldHandler'; 4 | import translateLabel from '../../../utils/translateLabel'; 5 | 6 | const RepeatDaily = ({ 7 | id, 8 | daily: { 9 | interval, 10 | }, 11 | handleChange, 12 | translations 13 | }) => ( 14 |
15 |
16 | {translateLabel(translations, 'repeat.daily.every')} 17 |
18 |
19 | 27 |
28 |
29 | {translateLabel(translations, 'repeat.daily.days')} 30 |
31 | 32 |
33 | ); 34 | RepeatDaily.propTypes = { 35 | id: PropTypes.string.isRequired, 36 | daily: PropTypes.shape({ 37 | interval: PropTypes.number.isRequired, 38 | }).isRequired, 39 | handleChange: PropTypes.func.isRequired, 40 | translations: PropTypes.oneOfType([PropTypes.object, PropTypes.func]).isRequired, 41 | }; 42 | 43 | export default RepeatDaily; 44 | -------------------------------------------------------------------------------- /src/lib/components/Repeat/Hourly/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import numericalFieldHandler from '../../../utils/numericalFieldHandler'; 4 | import translateLabel from '../../../utils/translateLabel'; 5 | 6 | const RepeatHourly = ({ 7 | id, 8 | hourly: { 9 | interval, 10 | }, 11 | handleChange, 12 | translations 13 | }) => ( 14 |
15 |
16 | {translateLabel(translations, 'repeat.hourly.every')} 17 |
18 |
19 | 27 |
28 |
29 | {translateLabel(translations, 'repeat.hourly.hours')} 30 |
31 |
32 | ); 33 | RepeatHourly.propTypes = { 34 | id: PropTypes.string.isRequired, 35 | hourly: PropTypes.shape({ 36 | interval: PropTypes.number.isRequired, 37 | }).isRequired, 38 | handleChange: PropTypes.func.isRequired, 39 | translations: PropTypes.oneOfType([PropTypes.object, PropTypes.func]).isRequired, 40 | }; 41 | 42 | export default RepeatHourly; 43 | -------------------------------------------------------------------------------- /src/demo/index.css: -------------------------------------------------------------------------------- 1 | @import '~bootstrap/dist/css/bootstrap.css'; 2 | @import '../lib/styles/index.css'; 3 | 4 | .app-navbar { 5 | display: flex; 6 | justify-content: space-between; 7 | 8 | padding: 1rem; 9 | 10 | background: #000; 11 | 12 | vertical-align: middle; 13 | font-size: 0.9rem; 14 | font-weight: 400; 15 | } 16 | @media screen and (max-width: 960px) { 17 | .app-header-github { 18 | margin-bottom: 2rem; 19 | } 20 | } 21 | 22 | .app-navbar a { 23 | opacity: 1; 24 | transition: 0.1s; 25 | color: white; 26 | } 27 | .app-navbar a:hover { 28 | opacity: 0.5; 29 | transition: 0.1s; 30 | text-decoration: none; 31 | } 32 | 33 | .app-navbar-ghlogo { 34 | height: 20px; 35 | width: 20px; 36 | } 37 | 38 | .app-header { 39 | padding: 1rem; 40 | background: #222; 41 | color: white; 42 | text-align: center; 43 | } 44 | 45 | .app-desc { 46 | padding: 1rem; 47 | background: #444; 48 | color: white; 49 | text-align: center; 50 | } 51 | 52 | .app { 53 | margin-top: 3rem; 54 | } 55 | 56 | ::-webkit-scrollbar { 57 | display: none; 58 | } 59 | 60 | .rrule { 61 | background-color: #ffecef; 62 | font-size: 80%; 63 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace; 64 | } 65 | 66 | .rrule-not-copied { 67 | color: #222; 68 | } 69 | 70 | .rrule-not-copied:focus { 71 | color: #222; 72 | } 73 | 74 | .rrule-copied { 75 | color: #888; 76 | } 77 | 78 | .rrule-copied:focus { 79 | color: #888; 80 | } 81 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/toString/computeMonthlyOnThe.js: -------------------------------------------------------------------------------- 1 | const computeMonthlyOnThe = (onThe) => { 2 | const repeat = {}; 3 | 4 | switch (onThe.which) { 5 | case 'First': 6 | repeat.bysetpos = 1; 7 | break; 8 | case 'Second': 9 | repeat.bysetpos = 2; 10 | break; 11 | case 'Third': 12 | repeat.bysetpos = 3; 13 | break; 14 | case 'Fourth': 15 | repeat.bysetpos = 4; 16 | break; 17 | case 'Last': 18 | repeat.bysetpos = -1; 19 | break; 20 | default: 21 | break; 22 | } 23 | 24 | switch (onThe.day) { 25 | case 'Monday': 26 | repeat.byweekday = [0]; 27 | break; 28 | case 'Tuesday': 29 | repeat.byweekday = [1]; 30 | break; 31 | case 'Wednesday': 32 | repeat.byweekday = [2]; 33 | break; 34 | case 'Thursday': 35 | repeat.byweekday = [3]; 36 | break; 37 | case 'Friday': 38 | repeat.byweekday = [4]; 39 | break; 40 | case 'Saturday': 41 | repeat.byweekday = [5]; 42 | break; 43 | case 'Sunday': 44 | repeat.byweekday = [6]; 45 | break; 46 | case 'Day': 47 | repeat.byweekday = [0, 1, 2, 3, 4, 5, 6]; 48 | break; 49 | case 'Weekday': 50 | repeat.byweekday = [0, 1, 2, 3, 4]; 51 | break; 52 | case 'Weekend day': 53 | repeat.byweekday = [5, 6]; 54 | break; 55 | default: 56 | break; 57 | } 58 | 59 | return repeat; 60 | }; 61 | 62 | export default computeMonthlyOnThe; 63 | -------------------------------------------------------------------------------- /src/lib/utils/computeRRule/toString/computeYearlyOnThe.js: -------------------------------------------------------------------------------- 1 | import { MONTHS } from '../../../constants/index'; 2 | 3 | const computeYearlyOnThe = (onThe) => { 4 | const repeat = {}; 5 | 6 | switch (onThe.which) { 7 | case 'First': 8 | repeat.bysetpos = 1; 9 | break; 10 | case 'Second': 11 | repeat.bysetpos = 2; 12 | break; 13 | case 'Third': 14 | repeat.bysetpos = 3; 15 | break; 16 | case 'Fourth': 17 | repeat.bysetpos = 4; 18 | break; 19 | case 'Last': 20 | repeat.bysetpos = -1; 21 | break; 22 | default: 23 | break; 24 | } 25 | 26 | switch (onThe.day) { 27 | case 'Monday': 28 | repeat.byweekday = [0]; 29 | break; 30 | case 'Tuesday': 31 | repeat.byweekday = [1]; 32 | break; 33 | case 'Wednesday': 34 | repeat.byweekday = [2]; 35 | break; 36 | case 'Thursday': 37 | repeat.byweekday = [3]; 38 | break; 39 | case 'Friday': 40 | repeat.byweekday = [4]; 41 | break; 42 | case 'Saturday': 43 | repeat.byweekday = [5]; 44 | break; 45 | case 'Sunday': 46 | repeat.byweekday = [6]; 47 | break; 48 | case 'Day': 49 | repeat.byweekday = [0, 1, 2, 3, 4, 5, 6]; 50 | break; 51 | case 'Weekday': 52 | repeat.byweekday = [0, 1, 2, 3, 4]; 53 | break; 54 | case 'Weekend day': 55 | repeat.byweekday = [5, 6]; 56 | break; 57 | default: 58 | break; 59 | } 60 | 61 | repeat.bymonth = MONTHS.indexOf(onThe.month) + 1; 62 | 63 | return repeat; 64 | }; 65 | 66 | export default computeYearlyOnThe; 67 | -------------------------------------------------------------------------------- /src/lib/components/Repeat/Yearly/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import RepeatYearlyOn from './On'; 4 | import RepeatYearlyOnThe from './OnThe'; 5 | 6 | const RepeatYearly = ({ 7 | id, 8 | yearly: { 9 | mode, 10 | on, 11 | onThe, 12 | options, 13 | }, 14 | handleChange, 15 | translations 16 | }) => { 17 | const isTheOnlyOneMode = option => options.modes === option; 18 | const isOptionAvailable = option => !options.modes || isTheOnlyOneMode(option); 19 | return ( 20 |
21 | {isOptionAvailable('on') && ( 22 | 30 | )} 31 | {isOptionAvailable('on the') && ( 32 | 40 | )} 41 |
42 | ); 43 | }; 44 | RepeatYearly.propTypes = { 45 | id: PropTypes.string.isRequired, 46 | yearly: PropTypes.shape({ 47 | mode: PropTypes.oneOf(['on', 'on the']).isRequired, 48 | on: PropTypes.object.isRequired, 49 | onThe: PropTypes.object.isRequired, 50 | options: PropTypes.shape({ 51 | modes: PropTypes.oneOf(['on', 'on the']), 52 | }).isRequired, 53 | }).isRequired, 54 | handleChange: PropTypes.func.isRequired, 55 | translations: PropTypes.oneOfType([PropTypes.object, PropTypes.func]).isRequired, 56 | }; 57 | 58 | export default RepeatYearly; 59 | -------------------------------------------------------------------------------- /src/lib/components/Repeat/Monthly/On.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import numericalFieldHandler from '../../../utils/numericalFieldHandler'; 4 | import translateLabel from '../../../utils/translateLabel'; 5 | 6 | const RepeatMonthlyOn = ({ 7 | id, 8 | mode, 9 | on, 10 | hasMoreModes, 11 | handleChange, 12 | translations 13 | }) => { 14 | const isActive = mode === 'on'; 15 | 16 | return ( 17 |
18 |
19 | {hasMoreModes && ( 20 | 29 | )} 30 |
31 |
32 | {translateLabel(translations, 'repeat.monthly.on_day')} 33 |
34 | 35 |
36 | 47 |
48 |
49 | ); 50 | }; 51 | RepeatMonthlyOn.propTypes = { 52 | id: PropTypes.string.isRequired, 53 | mode: PropTypes.oneOf(['on', 'on the']).isRequired, 54 | on: PropTypes.shape({ 55 | day: PropTypes.number.isRequired, 56 | }).isRequired, 57 | hasMoreModes: PropTypes.bool.isRequired, 58 | handleChange: PropTypes.func.isRequired, 59 | translations: PropTypes.oneOfType([PropTypes.object, PropTypes.func]).isRequired, 60 | }; 61 | 62 | export default RepeatMonthlyOn; 63 | -------------------------------------------------------------------------------- /src/lib/translations/english.js: -------------------------------------------------------------------------------- 1 | export default { 2 | locale: 'en-gb', 3 | invalid_rrule: "You provided an invalid RRule value to component. '%{value}' is not a correct RRule string.", 4 | months: { 5 | jan: 'Jan', 6 | feb: 'Feb', 7 | mar: 'Mar', 8 | apr: 'Apr', 9 | may: 'May', 10 | jun: 'Jun', 11 | jul: 'Jul', 12 | aug: 'Aug', 13 | sep: 'Sep', 14 | oct: 'Oct', 15 | nov: 'Nov', 16 | dec: 'Dec', 17 | }, 18 | days_short: { 19 | mon: 'Mon', 20 | tue: 'Tue', 21 | wed: 'Wed', 22 | thu: 'Thu', 23 | fri: 'Fri', 24 | sat: 'Sat', 25 | sun: 'Sun', 26 | }, 27 | days: { 28 | monday: 'Monday', 29 | tuesday: 'Tuesday', 30 | wednesday: 'Wednesday', 31 | thursday: 'Thursday', 32 | friday: 'Friday', 33 | saturday: 'Saturday', 34 | sunday: 'Sunday', 35 | day: 'Day', 36 | weekday: 'Weekday', 37 | 'weekend day': 'Weekend day', 38 | }, 39 | numerals: { 40 | first: 'First', 41 | second: 'Second', 42 | third: 'Third', 43 | fourth: 'Fourth', 44 | last: 'Last', 45 | }, 46 | start: { 47 | label: 'Start', 48 | tooltip: 'Datetime picker for start on date', 49 | }, 50 | repeat: { 51 | label: 'Repeat', 52 | yearly: { 53 | label: 'Yearly', 54 | on: 'on', 55 | on_the: 'on the', 56 | of: 'of', 57 | }, 58 | monthly: { 59 | label: 'Monthly', 60 | every: 'every', 61 | months: 'month(s)', 62 | on_day: 'on day', 63 | on_the: 'on the', 64 | }, 65 | weekly: { 66 | label: 'Weekly', 67 | every: 'every', 68 | weeks: 'week(s)', 69 | }, 70 | daily: { 71 | label: 'Daily', 72 | every: 'every', 73 | days: 'day(s)', 74 | }, 75 | hourly: { 76 | label: 'Hourly', 77 | every: 'every', 78 | hours: 'hour(s)', 79 | }, 80 | }, 81 | end: { 82 | label: 'End', 83 | tooltip: 'Datetime picker for end on date', 84 | never: 'Never', 85 | after: 'After', 86 | on_date: 'On date', 87 | executions: 'executions.', 88 | }, 89 | } 90 | -------------------------------------------------------------------------------- /src/lib/translations/german.js: -------------------------------------------------------------------------------- 1 | export default { 2 | locale: 'de', 3 | invalid_rrule: "Sie haben eine ungültige RRule an die Komponente übergeben. '%{value}' ist keine gültige RRule.", 4 | months: { 5 | jan: 'Jan', 6 | feb: 'Feb', 7 | mar: 'Mär', 8 | apr: 'Apr', 9 | may: 'Mai', 10 | jun: 'Jun', 11 | jul: 'Jul', 12 | aug: 'Aug', 13 | sep: 'Sep', 14 | oct: 'Okt', 15 | nov: 'Nov', 16 | dec: 'Dez', 17 | }, 18 | days_short: { 19 | mon: 'Mo', 20 | tue: 'Di', 21 | wed: 'Mi', 22 | thu: 'Do', 23 | fri: 'Fr', 24 | sat: 'Sa', 25 | sun: 'So', 26 | }, 27 | days: { 28 | monday: 'Montag', 29 | tuesday: 'Dienstag', 30 | wednesday: 'Mittwoch', 31 | thursday: 'Donnerstag', 32 | friday: 'Freitag', 33 | saturday: 'Samstag', 34 | sunday: 'Sonntag', 35 | day: 'Tag', 36 | weekday: 'Wochentag', 37 | 'weekend day': 'Wochenende', 38 | }, 39 | numerals: { 40 | first: 'Ersten', 41 | second: 'Zweiten', 42 | third: 'Dritten', 43 | fourth: 'Vierten', 44 | last: 'Letzten', 45 | }, 46 | start: { 47 | label: 'Start', 48 | tooltip: 'Startdatum des Zeitplans', 49 | }, 50 | repeat: { 51 | label: 'Wiederholen', 52 | yearly: { 53 | label: 'Jährlich', 54 | on: 'am', 55 | on_the: 'an dem', 56 | of: 'von', 57 | }, 58 | monthly: { 59 | label: 'Monatlich', 60 | every: 'Jeden', 61 | months: 'Monat(e)', 62 | on_day: 'am Tag', 63 | on_the: 'am', 64 | }, 65 | weekly: { 66 | label: 'Wöchentlich', 67 | every: 'Jede', 68 | weeks: 'Woche(n)', 69 | }, 70 | daily: { 71 | label: 'Täglich', 72 | every: 'Jeden', 73 | days: 'Tag(e)', 74 | }, 75 | hourly: { 76 | label: 'Stündlich', 77 | every: 'Jede', 78 | hours: 'Stunde(n)', 79 | }, 80 | }, 81 | end: { 82 | label: 'Ende', 83 | tooltip: 'Ende des Zeitplans', 84 | never: 'Niemals', 85 | after: 'Nach', 86 | on_date: 'Am', 87 | executions: 'Ausführungen.', 88 | }, 89 | }; 90 | -------------------------------------------------------------------------------- /config/paths.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const fs = require('fs'); 5 | const url = require('url'); 6 | 7 | // Make sure any symlinks in the project folder are resolved: 8 | // https://github.com/facebookincubator/create-react-app/issues/637 9 | const appDirectory = fs.realpathSync(process.cwd()); 10 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath); 11 | 12 | const envPublicUrl = process.env.PUBLIC_URL; 13 | 14 | function ensureSlash(path, needsSlash) { 15 | const hasSlash = path.endsWith('/'); 16 | if (hasSlash && !needsSlash) { 17 | return path.substr(path, path.length - 1); 18 | } else if (!hasSlash && needsSlash) { 19 | return `${path}/`; 20 | } else { 21 | return path; 22 | } 23 | } 24 | 25 | const getPublicUrl = appPackageJson => 26 | envPublicUrl || require(appPackageJson).homepage; 27 | 28 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer 29 | // "public path" at which the app is served. 30 | // Webpack needs to know it to put the right