dce-reactkit 4.0.0 → 4.0.2-beta-simple-date-chooser.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +355 -91
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/SimpleDateChooser.d.ts +3 -1
- package/dist/cjs/types/components/SimpleTimeChooser.d.ts +20 -0
- package/dist/cjs/types/index.d.ts +2 -1
- package/dist/cjs/types/types/ReactKitErrorCode.d.ts +3 -1
- package/dist/esm/index.js +355 -92
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/SimpleDateChooser.d.ts +3 -1
- package/dist/esm/types/components/SimpleTimeChooser.d.ts +20 -0
- package/dist/esm/types/index.d.ts +2 -1
- package/dist/esm/types/types/ReactKitErrorCode.d.ts +3 -1
- package/dist/index.d.ts +41 -17
- package/package.json +1 -1
- package/src/components/LogReviewer.tsx +2 -2
- package/src/components/SimpleDateChooser.tsx +397 -119
- package/src/components/SimpleTimeChooser.tsx +196 -0
- package/src/index.ts +2 -0
- package/src/types/LogSource.ts +1 -1
- package/src/types/ReactKitErrorCode.tsx +3 -1
package/dist/cjs/index.js
CHANGED
|
@@ -55,7 +55,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
// Highest error code =
|
|
58
|
+
// Highest error code = DRK36
|
|
59
59
|
/**
|
|
60
60
|
* List of error codes built into the react kit
|
|
61
61
|
* @author Gabe Abrams
|
|
@@ -66,6 +66,8 @@ var ReactKitErrorCode;
|
|
|
66
66
|
ReactKitErrorCode["NoCode"] = "DRK2";
|
|
67
67
|
ReactKitErrorCode["SessionExpired"] = "DRK3";
|
|
68
68
|
ReactKitErrorCode["NoCACCLSendRequestFunction"] = "DRK7";
|
|
69
|
+
ReactKitErrorCode["SimpleDateChooserInvalidDateRange"] = "DRK35";
|
|
70
|
+
ReactKitErrorCode["SimpleDateChooserInvalidNumMonths"] = "DRK36";
|
|
69
71
|
})(ReactKitErrorCode || (ReactKitErrorCode = {}));
|
|
70
72
|
var ReactKitErrorCode$1 = ReactKitErrorCode;
|
|
71
73
|
|
|
@@ -2547,6 +2549,19 @@ const ButtonInputGroup = (props) => {
|
|
|
2547
2549
|
: children))));
|
|
2548
2550
|
};
|
|
2549
2551
|
|
|
2552
|
+
// Constants
|
|
2553
|
+
const ORDINALS = ['th', 'st', 'nd', 'rd'];
|
|
2554
|
+
/**
|
|
2555
|
+
* Get a number's ordinal
|
|
2556
|
+
* @author Gabe Abrams
|
|
2557
|
+
* @param num the number being analyzed
|
|
2558
|
+
* @returns ordinal
|
|
2559
|
+
*/
|
|
2560
|
+
const getOrdinal = (num) => {
|
|
2561
|
+
var _a, _b;
|
|
2562
|
+
return ((_b = (_a = ORDINALS[(num - 20) % 10]) !== null && _a !== void 0 ? _a : ORDINALS[num]) !== null && _b !== void 0 ? _b : ORDINALS[0]);
|
|
2563
|
+
};
|
|
2564
|
+
|
|
2550
2565
|
const monthNames = [
|
|
2551
2566
|
{ short: 'Jan', full: 'January' },
|
|
2552
2567
|
{ short: 'Feb', full: 'February' },
|
|
@@ -2575,19 +2590,6 @@ const getMonthName = (month) => {
|
|
|
2575
2590
|
return ((_a = monthNames[month - 1]) !== null && _a !== void 0 ? _a : monthNames[0]);
|
|
2576
2591
|
};
|
|
2577
2592
|
|
|
2578
|
-
// Constants
|
|
2579
|
-
const ORDINALS = ['th', 'st', 'nd', 'rd'];
|
|
2580
|
-
/**
|
|
2581
|
-
* Get a number's ordinal
|
|
2582
|
-
* @author Gabe Abrams
|
|
2583
|
-
* @param num the number being analyzed
|
|
2584
|
-
* @returns ordinal
|
|
2585
|
-
*/
|
|
2586
|
-
const getOrdinal = (num) => {
|
|
2587
|
-
var _a, _b;
|
|
2588
|
-
return ((_b = (_a = ORDINALS[(num - 20) % 10]) !== null && _a !== void 0 ? _a : ORDINALS[num]) !== null && _b !== void 0 ? _b : ORDINALS[0]);
|
|
2589
|
-
};
|
|
2590
|
-
|
|
2591
2593
|
/**
|
|
2592
2594
|
* Get current time info in US Boston Eastern Time, independent of machine
|
|
2593
2595
|
* timezone
|
|
@@ -2651,35 +2653,86 @@ const getTimeInfoInET = (dateOrTimestamp) => {
|
|
|
2651
2653
|
/**
|
|
2652
2654
|
* A very simple, lightweight date chooser
|
|
2653
2655
|
* @author Gabe Abrams
|
|
2656
|
+
* @author Gardenia Liu
|
|
2654
2657
|
*/
|
|
2655
2658
|
/*------------------------------------------------------------------------*/
|
|
2656
|
-
/*
|
|
2659
|
+
/* -------------------------------- State ------------------------------- */
|
|
2657
2660
|
/*------------------------------------------------------------------------*/
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2661
|
+
/* -------------- Views ------------- */
|
|
2662
|
+
var View;
|
|
2663
|
+
(function (View) {
|
|
2664
|
+
// Date chooser
|
|
2665
|
+
View["DateChooser"] = "DateChooser";
|
|
2666
|
+
// Invalid date
|
|
2667
|
+
View["InvalidDate"] = "InvalidDate";
|
|
2668
|
+
})(View || (View = {}));
|
|
2669
|
+
/* ------------- Actions ------------ */
|
|
2670
|
+
// Types of actions
|
|
2671
|
+
var ActionType$a;
|
|
2672
|
+
(function (ActionType) {
|
|
2673
|
+
// Fix invalid date so it is now in range
|
|
2674
|
+
ActionType["FixInvalidDate"] = "FixInvalidDate";
|
|
2675
|
+
})(ActionType$a || (ActionType$a = {}));
|
|
2676
|
+
/**
|
|
2677
|
+
* Reducer that executes actions
|
|
2678
|
+
* @author Gardenia Liu
|
|
2679
|
+
* @param state current state
|
|
2680
|
+
* @param action action to execute
|
|
2681
|
+
* @returns updated state
|
|
2682
|
+
*/
|
|
2683
|
+
const reducer$b = (state, action) => {
|
|
2684
|
+
switch (action.type) {
|
|
2685
|
+
case ActionType$a.FixInvalidDate: {
|
|
2686
|
+
return Object.assign(Object.assign({}, state), { view: View.DateChooser });
|
|
2687
|
+
}
|
|
2688
|
+
default: {
|
|
2689
|
+
return state;
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2692
|
+
};
|
|
2693
|
+
/*------------------------------------------------------------------------*/
|
|
2694
|
+
/* --------------------------- Static Helpers --------------------------- */
|
|
2695
|
+
/*------------------------------------------------------------------------*/
|
|
2696
|
+
/**
|
|
2697
|
+
* Get the list of choices in the date chooser given props
|
|
2698
|
+
* @author Gardenia Liu
|
|
2699
|
+
* @author Gabe Abrams
|
|
2700
|
+
* @param opts object containing all arguments
|
|
2701
|
+
* @param opts.numMonthsToShow number of months to show
|
|
2702
|
+
* @param opts.dontAllowPast if true, the user isn't allowed to select dates in the past
|
|
2703
|
+
* @param opts.dontAllowFuture if true, the user isn't allowed to select dates in the future
|
|
2704
|
+
* @returns choices
|
|
2705
|
+
*/
|
|
2706
|
+
const getChoices = (opts) => {
|
|
2707
|
+
// Destructure props
|
|
2708
|
+
const { dontAllowFuture, dontAllowPast, numMonthsToShow = 6, } = opts;
|
|
2670
2709
|
// Determine the set of choices allowed
|
|
2671
2710
|
const today = getTimeInfoInET();
|
|
2672
2711
|
const choices = [];
|
|
2673
2712
|
let startYear = today.year;
|
|
2674
2713
|
let startMonth = today.month;
|
|
2675
|
-
|
|
2714
|
+
// Don't allow past or future dates
|
|
2715
|
+
if (dontAllowPast && dontAllowFuture) {
|
|
2716
|
+
throw new ErrorWithCode('No past or future dates allowed', ReactKitErrorCode$1.SimpleDateChooserInvalidDateRange);
|
|
2717
|
+
}
|
|
2718
|
+
// Require numMonthsToShow to be positive
|
|
2719
|
+
if (numMonthsToShow <= 0) {
|
|
2720
|
+
throw new ErrorWithCode('numMonthsToShow must be positive', ReactKitErrorCode$1.SimpleDateChooserInvalidNumMonths);
|
|
2721
|
+
}
|
|
2722
|
+
// Recalculate startMonth and startYear when allowing past dates
|
|
2723
|
+
if (!dontAllowPast) {
|
|
2676
2724
|
startMonth -= Math.max(0, numMonthsToShow - 1);
|
|
2677
2725
|
while (startMonth <= 0) {
|
|
2678
2726
|
startMonth += 12;
|
|
2679
2727
|
startYear -= 1;
|
|
2680
2728
|
}
|
|
2681
2729
|
}
|
|
2682
|
-
|
|
2730
|
+
// Calculate total number of months to show
|
|
2731
|
+
let totalMonthsToShow = numMonthsToShow;
|
|
2732
|
+
if (!dontAllowPast && !dontAllowFuture) {
|
|
2733
|
+
totalMonthsToShow = totalMonthsToShow * 2 - 1;
|
|
2734
|
+
}
|
|
2735
|
+
for (let i = 0; i < totalMonthsToShow; i++) {
|
|
2683
2736
|
// Get month and year info
|
|
2684
2737
|
const unmoddedMonth = (startMonth + i);
|
|
2685
2738
|
let month = unmoddedMonth;
|
|
@@ -2698,23 +2751,25 @@ const SimpleDateChooser = (props) => {
|
|
|
2698
2751
|
// Figure out which days are allowed
|
|
2699
2752
|
const days = [];
|
|
2700
2753
|
const numDaysInMonth = (new Date(year, month, 0)).getDate();
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
days.push(day);
|
|
2754
|
+
// Current month
|
|
2755
|
+
if (month === today.month && year === today.year) {
|
|
2756
|
+
// Past selection: add all previous days of the month
|
|
2757
|
+
if (!dontAllowPast) {
|
|
2758
|
+
for (let day = 1; day < today.day; day++) {
|
|
2759
|
+
days.push(day);
|
|
2760
|
+
}
|
|
2709
2761
|
}
|
|
2710
|
-
|
|
2711
|
-
else {
|
|
2762
|
+
days.push(today.day); // Add current day
|
|
2712
2763
|
// Future selection: add all remaining days of the month
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2764
|
+
if (!dontAllowFuture) {
|
|
2765
|
+
for (let day = today.day + 1; day <= numDaysInMonth; day++) {
|
|
2766
|
+
days.push(day);
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2770
|
+
else { // Past or future month
|
|
2771
|
+
// Include all days in the month
|
|
2772
|
+
for (let day = 1; day <= numDaysInMonth; day++) {
|
|
2718
2773
|
days.push(day);
|
|
2719
2774
|
}
|
|
2720
2775
|
}
|
|
@@ -2725,36 +2780,262 @@ const SimpleDateChooser = (props) => {
|
|
|
2725
2780
|
days,
|
|
2726
2781
|
});
|
|
2727
2782
|
}
|
|
2728
|
-
//
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2783
|
+
// Return choices
|
|
2784
|
+
return choices;
|
|
2785
|
+
};
|
|
2786
|
+
/**
|
|
2787
|
+
* Checks whether a given date is outside the valid range of allowed choices
|
|
2788
|
+
* @author Gardenia Liu
|
|
2789
|
+
* @param opts object containing all arguments
|
|
2790
|
+
* @param opts.month 1-indexed month
|
|
2791
|
+
* @param opts.day day of the month
|
|
2792
|
+
* @param opts.year full year
|
|
2793
|
+
* @param opts.choices valid date choices
|
|
2794
|
+
* @returns true if date is out of range
|
|
2795
|
+
*/
|
|
2796
|
+
const isDateOutOfRange = (opts) => {
|
|
2797
|
+
const { month, day, year, choices, } = opts;
|
|
2798
|
+
return !choices.some((choice) => {
|
|
2799
|
+
return (choice.month === month
|
|
2800
|
+
&& choice.year === year
|
|
2801
|
+
&& choice.days.includes(day));
|
|
2802
|
+
});
|
|
2803
|
+
};
|
|
2804
|
+
/*------------------------------------------------------------------------*/
|
|
2805
|
+
/* ------------------------------ Component ----------------------------- */
|
|
2806
|
+
/*------------------------------------------------------------------------*/
|
|
2807
|
+
const SimpleDateChooser = (props) => {
|
|
2808
|
+
/*------------------------------------------------------------------------*/
|
|
2809
|
+
/* -------------------------------- Setup ------------------------------- */
|
|
2810
|
+
/*------------------------------------------------------------------------*/
|
|
2811
|
+
/* -------------- Props ------------- */
|
|
2812
|
+
const { ariaLabel, name, dontAllowPast, dontAllowFuture, numMonthsToShow, onChange, month, day, year, } = props;
|
|
2813
|
+
// Get choices
|
|
2814
|
+
const choices = getChoices({
|
|
2815
|
+
numMonthsToShow,
|
|
2816
|
+
dontAllowPast,
|
|
2817
|
+
dontAllowFuture,
|
|
2818
|
+
});
|
|
2819
|
+
/* -------------- State ------------- */
|
|
2820
|
+
// Check if the currently selected date is out of range
|
|
2821
|
+
const currentSelectedDateOutOfRange = isDateOutOfRange({
|
|
2822
|
+
month,
|
|
2823
|
+
day,
|
|
2824
|
+
year,
|
|
2825
|
+
choices,
|
|
2826
|
+
});
|
|
2827
|
+
// Initial state
|
|
2828
|
+
const initialState = {
|
|
2829
|
+
view: (currentSelectedDateOutOfRange
|
|
2830
|
+
? View.InvalidDate
|
|
2831
|
+
: View.DateChooser),
|
|
2832
|
+
};
|
|
2833
|
+
// Initialize state
|
|
2834
|
+
const [state, dispatch] = React.useReducer(reducer$b, initialState);
|
|
2835
|
+
// Destructure common state
|
|
2836
|
+
const { view, } = state;
|
|
2837
|
+
/*------------------------------------------------------------------------*/
|
|
2838
|
+
/* ------------------------- Component Functions ------------------------ */
|
|
2839
|
+
/*------------------------------------------------------------------------*/
|
|
2840
|
+
/**
|
|
2841
|
+
* Ask the user if they want to edit an invalid date
|
|
2842
|
+
* @author Gardenia Liu
|
|
2843
|
+
* @author Gabe Abrams
|
|
2844
|
+
*/
|
|
2845
|
+
const askToEditInvalidDate = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
2846
|
+
// Ask the user if they want to edit the date
|
|
2847
|
+
const confirmed = yield confirm('Are you sure?', 'The current date is outside the normal range. If you edit it, you\'ll need to choose a new date in the normal range.', {
|
|
2848
|
+
confirmButtonText: 'Edit Date',
|
|
2849
|
+
});
|
|
2850
|
+
// Check if user confirmed
|
|
2851
|
+
if (confirmed) {
|
|
2852
|
+
// Update the date to today
|
|
2853
|
+
const today = getTimeInfoInET();
|
|
2854
|
+
onChange(today.month, today.day, today.year);
|
|
2855
|
+
// Update state
|
|
2856
|
+
dispatch({
|
|
2857
|
+
type: ActionType$a.FixInvalidDate,
|
|
2745
2858
|
});
|
|
2746
2859
|
}
|
|
2747
2860
|
});
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2861
|
+
/*------------------------------------------------------------------------*/
|
|
2862
|
+
/* ------------------------------- Render ------------------------------- */
|
|
2863
|
+
/*------------------------------------------------------------------------*/
|
|
2864
|
+
/*----------------------------------------*/
|
|
2865
|
+
/* ---------------- Views --------------- */
|
|
2866
|
+
/*----------------------------------------*/
|
|
2867
|
+
// Body that will be filled with the current view
|
|
2868
|
+
let body;
|
|
2869
|
+
/* ---------- DateChooser ---------- */
|
|
2870
|
+
if (view === View.DateChooser) {
|
|
2871
|
+
// Create lists of options
|
|
2872
|
+
const monthOptions = [];
|
|
2873
|
+
const dayOptions = [];
|
|
2874
|
+
// Render each option and add it to the list
|
|
2875
|
+
choices.forEach((choice) => {
|
|
2876
|
+
// Create month option
|
|
2877
|
+
monthOptions.push(React__default["default"].createElement("option", { key: `${choice.year}-${choice.month}`, value: `${choice.month}-${choice.year}`, "aria-label": `choose ${choice.choiceName}`, onSelect: () => {
|
|
2878
|
+
onChange(choice.month, choice.days[0], choice.year);
|
|
2879
|
+
} }, choice.choiceName));
|
|
2880
|
+
// This is the currently selected month
|
|
2881
|
+
if (month === choice.month) {
|
|
2882
|
+
// Create day options
|
|
2883
|
+
choice.days.forEach((dayChoice) => {
|
|
2884
|
+
const ordinal = getOrdinal(dayChoice);
|
|
2885
|
+
dayOptions.push(React__default["default"].createElement("option", { key: `${choice.year}-${choice.month}-${dayChoice}`, value: dayChoice, "aria-label": `choose date ${dayChoice}` },
|
|
2886
|
+
dayChoice,
|
|
2887
|
+
ordinal));
|
|
2888
|
+
});
|
|
2889
|
+
}
|
|
2890
|
+
});
|
|
2891
|
+
// Create body
|
|
2892
|
+
body = (React__default["default"].createElement("div", { className: "SimpleDateChooser-inner-container d-inline-block", "aria-label": `date chooser with selected date: ${month}/${day}/${year}` },
|
|
2893
|
+
React__default["default"].createElement("select", { "aria-label": `month for ${ariaLabel}`, className: "custom-select d-inline-block mr-1", style: { width: 'auto' }, id: `SimpleDateChooser-${name}-month`, value: `${month}-${year}`, onChange: (e) => {
|
|
2894
|
+
const choice = choices[e.target.selectedIndex];
|
|
2895
|
+
// Change day, month, and year
|
|
2896
|
+
onChange(choice.month, choice.days[0], choice.year);
|
|
2897
|
+
} }, monthOptions),
|
|
2898
|
+
React__default["default"].createElement("select", { "aria-label": `day for ${ariaLabel}`, className: "custom-select d-inline-block", style: { width: 'auto' }, id: `SimpleDateChooser-${name}-day`, value: day, onChange: (e) => {
|
|
2899
|
+
// Only change the day
|
|
2900
|
+
onChange(month, Number.parseInt(e.target.value, 10), year);
|
|
2901
|
+
} }, dayOptions)));
|
|
2902
|
+
}
|
|
2903
|
+
/* --------- DateOutOfRange --------- */
|
|
2904
|
+
if (view === View.InvalidDate) {
|
|
2905
|
+
body = (React__default["default"].createElement("div", { className: "SimpleDateChooser-inner-container d-inline-block" },
|
|
2906
|
+
React__default["default"].createElement("button", { type: "button", className: "btn btn-light", onClick: askToEditInvalidDate, "aria-label": `edit date for ${ariaLabel}` },
|
|
2907
|
+
getMonthName(month).full,
|
|
2908
|
+
' ',
|
|
2909
|
+
day,
|
|
2910
|
+
getOrdinal(day),
|
|
2911
|
+
",",
|
|
2912
|
+
' ',
|
|
2913
|
+
year),
|
|
2914
|
+
React__default["default"].createElement("button", { type: "button", className: "btn btn-secondary", onClick: askToEditInvalidDate, "aria-label": `edit date for ${ariaLabel}` }, "Edit")));
|
|
2915
|
+
}
|
|
2916
|
+
/*----------------------------------------*/
|
|
2917
|
+
/* --------------- Main UI -------------- */
|
|
2918
|
+
/*----------------------------------------*/
|
|
2919
|
+
return (React__default["default"].createElement("span", { className: "SimpleDateChooser-outer-container" }, body));
|
|
2920
|
+
};
|
|
2921
|
+
|
|
2922
|
+
/**
|
|
2923
|
+
* Pad a number with zeros on the left (e.g. 5 becomes 05 with 2 digit padding)
|
|
2924
|
+
* @author Gabe Abrams
|
|
2925
|
+
* @param num the number to pad
|
|
2926
|
+
* @param numDigits the minimum number of digits before the decimal
|
|
2927
|
+
* @returns padded number
|
|
2928
|
+
*/
|
|
2929
|
+
const padZerosLeft = (num, numDigits) => {
|
|
2930
|
+
// Convert to string
|
|
2931
|
+
let out = String(num);
|
|
2932
|
+
// Add zeros
|
|
2933
|
+
while (out.split('.')[0].length < numDigits) {
|
|
2934
|
+
out = `0${out}`;
|
|
2935
|
+
}
|
|
2936
|
+
// Return
|
|
2937
|
+
return out;
|
|
2938
|
+
};
|
|
2939
|
+
|
|
2940
|
+
/**
|
|
2941
|
+
* A very simple, lightweight time chooser
|
|
2942
|
+
* @author Gardenia Liu
|
|
2943
|
+
*/
|
|
2944
|
+
/*------------------------------------------------------------------------*/
|
|
2945
|
+
/* ------------------------------ Constants ----------------------------- */
|
|
2946
|
+
/*------------------------------------------------------------------------*/
|
|
2947
|
+
// Allowed intervals between options
|
|
2948
|
+
const ALLOWED_INTERVALS = [15, 30, 60]; // min
|
|
2949
|
+
// Default interval to use if an unsupported interval is passed in
|
|
2950
|
+
const DEFAULT_INTERVAL = ALLOWED_INTERVALS[0]; // min
|
|
2951
|
+
/*------------------------------------------------------------------------*/
|
|
2952
|
+
/* ------------------------------ Component ----------------------------- */
|
|
2953
|
+
/*------------------------------------------------------------------------*/
|
|
2954
|
+
const SimpleTimeChooser = (props) => {
|
|
2955
|
+
/*------------------------------------------------------------------------*/
|
|
2956
|
+
/* -------------------------------- Setup ------------------------------- */
|
|
2957
|
+
/*------------------------------------------------------------------------*/
|
|
2958
|
+
/* -------------- Props ------------- */
|
|
2959
|
+
const { ariaLabel, name, hour, minute, onChange, } = props;
|
|
2960
|
+
let { intervalMin = DEFAULT_INTERVAL, } = props;
|
|
2961
|
+
// Use default interval if not supported
|
|
2962
|
+
if (!ALLOWED_INTERVALS.includes(intervalMin)) {
|
|
2963
|
+
intervalMin = DEFAULT_INTERVAL;
|
|
2964
|
+
}
|
|
2965
|
+
/*------------------------------------------------------------------------*/
|
|
2966
|
+
/* ------------------------- Component Functions ------------------------ */
|
|
2967
|
+
/*------------------------------------------------------------------------*/
|
|
2968
|
+
/**
|
|
2969
|
+
* Convert number of minutes since midnight into 24hour and minute format
|
|
2970
|
+
* @author Gabe Abrams
|
|
2971
|
+
* @param minSinceMidnight total minutes since midnight
|
|
2972
|
+
* @returns hours (24) and minutes
|
|
2973
|
+
*/
|
|
2974
|
+
const convertMinSinceMidnightToHoursAndMin = (minSinceMidnight) => {
|
|
2975
|
+
return {
|
|
2976
|
+
hours: Math.floor(minSinceMidnight / 60),
|
|
2977
|
+
minutes: minSinceMidnight % 60,
|
|
2978
|
+
};
|
|
2979
|
+
};
|
|
2980
|
+
/**
|
|
2981
|
+
* Convert time in minutes into HH:MM format
|
|
2982
|
+
* @author Gardenia Liu
|
|
2983
|
+
* @param totalMinutes total minutes since midnight
|
|
2984
|
+
* @returns formatted time string
|
|
2985
|
+
*/
|
|
2986
|
+
const formatTime = (totalMinutes) => {
|
|
2987
|
+
// Handle special cases
|
|
2988
|
+
if (totalMinutes === 0) {
|
|
2989
|
+
return '12:00 Midnight';
|
|
2990
|
+
}
|
|
2991
|
+
if (totalMinutes === 12 * 60) {
|
|
2992
|
+
return '12:00 Noon';
|
|
2993
|
+
}
|
|
2994
|
+
// All normal cases:
|
|
2995
|
+
const timeInfo = convertMinSinceMidnightToHoursAndMin(totalMinutes);
|
|
2996
|
+
let { hours } = timeInfo;
|
|
2997
|
+
const { minutes } = timeInfo;
|
|
2998
|
+
// Process 24hr -> 12hr
|
|
2999
|
+
const isAM = (hours < 12);
|
|
3000
|
+
if (hours === 0) {
|
|
3001
|
+
hours = 12;
|
|
3002
|
+
}
|
|
3003
|
+
else if (hours > 12) {
|
|
3004
|
+
hours %= 12;
|
|
3005
|
+
}
|
|
3006
|
+
// Pad with zeros
|
|
3007
|
+
const paddedMinutes = padZerosLeft(minutes, 2);
|
|
3008
|
+
// Assemble time string
|
|
3009
|
+
return `${hours}:${paddedMinutes} ${isAM ? 'AM' : 'PM'}`;
|
|
3010
|
+
};
|
|
3011
|
+
/*------------------------------------------------------------------------*/
|
|
3012
|
+
/* ------------------------------- Render ------------------------------- */
|
|
3013
|
+
/*------------------------------------------------------------------------*/
|
|
3014
|
+
/*----------------------------------------*/
|
|
3015
|
+
/* --------------- Main UI -------------- */
|
|
3016
|
+
/*----------------------------------------*/
|
|
3017
|
+
// Generate list of time options
|
|
3018
|
+
const times = [];
|
|
3019
|
+
for (let time = 0; time < 24 * 60; time += intervalMin) {
|
|
3020
|
+
times.push(formatTime(time));
|
|
3021
|
+
}
|
|
3022
|
+
// Currently selected time in minutes since midnight
|
|
3023
|
+
const selectedTimeMin = hour * 60 + minute;
|
|
3024
|
+
// Create choice options
|
|
3025
|
+
const timeOptions = times.map((timeString, timeIndex) => {
|
|
3026
|
+
const numMinutesForChoice = timeIndex * intervalMin;
|
|
3027
|
+
// Render the option
|
|
3028
|
+
return (React__default["default"].createElement("option", { key: numMinutesForChoice, value: numMinutesForChoice, "aria-label": `choose ${timeString}` }, timeString));
|
|
3029
|
+
});
|
|
3030
|
+
return (React__default["default"].createElement("div", { className: "SimpleTimeChooser-container", "aria-label": `time chooser with selected time: ${formatTime(selectedTimeMin)}` },
|
|
3031
|
+
React__default["default"].createElement("select", { "aria-label": `time for ${ariaLabel}`, className: "custom-select d-inline-block", style: { width: 'auto' }, id: `SimpleTimeChooser-${name}-time`, value: selectedTimeMin, onChange: (e) => {
|
|
3032
|
+
// Parse selector value (string)
|
|
3033
|
+
const newTime = Number.parseInt(e.target.value, 10);
|
|
3034
|
+
// Convert minutes since midnight to hour and minute
|
|
3035
|
+
const timeInfo = convertMinSinceMidnightToHoursAndMin(newTime);
|
|
3036
|
+
// Notify parent
|
|
3037
|
+
onChange(timeInfo.hours, timeInfo.minutes);
|
|
3038
|
+
} }, timeOptions)));
|
|
2758
3039
|
};
|
|
2759
3040
|
|
|
2760
3041
|
/**
|
|
@@ -4851,14 +5132,14 @@ const LogReviewer = (props) => {
|
|
|
4851
5132
|
if (expandedFilterDrawer) {
|
|
4852
5133
|
if (expandedFilterDrawer === FilterDrawer.Date) {
|
|
4853
5134
|
filterDrawer = (React__default["default"].createElement(TabBox, { title: "Date" },
|
|
4854
|
-
React__default["default"].createElement(SimpleDateChooser, { ariaLabel: "filter start date", name: "filter-start-date", year: dateFilterState.startDate.year, month: dateFilterState.startDate.month, day: dateFilterState.startDate.day,
|
|
5135
|
+
React__default["default"].createElement(SimpleDateChooser, { ariaLabel: "filter start date", name: "filter-start-date", year: dateFilterState.startDate.year, month: dateFilterState.startDate.month, day: dateFilterState.startDate.day, dontAllowFuture: true, numMonthsToShow: 36, onChange: (month, day, year) => {
|
|
4855
5136
|
dateFilterState.startDate = { month, day, year };
|
|
4856
5137
|
handleDateRangeUpdated(dateFilterState);
|
|
4857
5138
|
} }),
|
|
4858
5139
|
' ',
|
|
4859
5140
|
"to",
|
|
4860
5141
|
' ',
|
|
4861
|
-
React__default["default"].createElement(SimpleDateChooser, { ariaLabel: "filter end date", name: "filter-end-date", year: dateFilterState.endDate.year, month: dateFilterState.endDate.month, day: dateFilterState.endDate.day,
|
|
5142
|
+
React__default["default"].createElement(SimpleDateChooser, { ariaLabel: "filter end date", name: "filter-end-date", year: dateFilterState.endDate.year, month: dateFilterState.endDate.month, day: dateFilterState.endDate.day, dontAllowFuture: true, numMonthsToShow: 12, onChange: (month, day, year) => {
|
|
4862
5143
|
if (year < dateFilterState.startDate.year
|
|
4863
5144
|
|| (year === dateFilterState.startDate.year
|
|
4864
5145
|
&& month < dateFilterState.startDate.month)
|
|
@@ -15338,24 +15619,6 @@ const padDecimalZeros = (num, numDigits) => {
|
|
|
15338
15619
|
return out;
|
|
15339
15620
|
};
|
|
15340
15621
|
|
|
15341
|
-
/**
|
|
15342
|
-
* Pad a number with zeros on the left (e.g. 5 becomes 05 with 2 digit padding)
|
|
15343
|
-
* @author Gabe Abrams
|
|
15344
|
-
* @param num the number to pad
|
|
15345
|
-
* @param numDigits the minimum number of digits before the decimal
|
|
15346
|
-
* @returns padded number
|
|
15347
|
-
*/
|
|
15348
|
-
const padZerosLeft = (num, numDigits) => {
|
|
15349
|
-
// Convert to string
|
|
15350
|
-
let out = String(num);
|
|
15351
|
-
// Add zeros
|
|
15352
|
-
while (out.split('.')[0].length < numDigits) {
|
|
15353
|
-
out = `0${out}`;
|
|
15354
|
-
}
|
|
15355
|
-
// Return
|
|
15356
|
-
return out;
|
|
15357
|
-
};
|
|
15358
|
-
|
|
15359
15622
|
/**
|
|
15360
15623
|
* Stub a server endpoint response
|
|
15361
15624
|
* @author Gabe Abrams
|
|
@@ -16268,6 +16531,7 @@ exports.PopSuccessMark = PopSuccessMark;
|
|
|
16268
16531
|
exports.RadioButton = RadioButton;
|
|
16269
16532
|
exports.ReactKitErrorCode = ReactKitErrorCode$1;
|
|
16270
16533
|
exports.SimpleDateChooser = SimpleDateChooser;
|
|
16534
|
+
exports.SimpleTimeChooser = SimpleTimeChooser;
|
|
16271
16535
|
exports.TabBox = TabBox;
|
|
16272
16536
|
exports.ToggleSwitch = ToggleSwitch;
|
|
16273
16537
|
exports.Tooltip = Tooltip;
|