PluginProbe ʕ •ᴥ•ʔ
Presto Player / trunk
Presto Player vtrunk
4.3.0 4.2.4 4.2.3 4.2.2 4.2.0 4.2.1 trunk 1.10.0 1.10.1 1.10.2 1.11.0 1.12.0 1.13.0 1.14.0 1.14.1 1.5.10 1.5.11 1.5.12 1.5.13 1.5.14 1.5.15 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.10 1.6.11 1.6.12 1.6.13 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.13 2.0.14 2.0.15 2.0.16 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.2.0 2.2.1 2.2.2 2.2.3 2.2.3-beta1 2.3.0 2.3.1 2.3.2 2.3.3 3.0.0 3.0.0-beta1 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.1.0 3.1.1 3.1.2 3.1.3 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4
presto-player / src / admin / dashboard / components / ChooseDate.js
presto-player / src / admin / dashboard / components Last commit date
Emails 1 month ago EngagementChart 1 month ago MediaHub 1 month ago Onboarding 1 month ago Popup 1 month ago Skeletons 1 week ago WhatsNew 1 month ago charts 1 month ago test 1 month ago AdminMenuSync.js 1 month ago ChartEmptyState.js 1 month ago ChooseDate.js 1 month ago ColorPicker.js 1 month ago ExtendPlugins.js 1 month ago Filters.js 1 month ago Link.js 1 month ago Navbar.js 1 week ago NoFound.js 1 month ago PageHeader.js 1 month ago PluginRecommendations.js 1 month ago PostScheduleField.js 1 month ago PrestoPlayerIcon.js 1 month ago ProGateOverlay.js 1 month ago QuickAccess.js 1 month ago RankedTable.js 1 month ago StatCard.js 1 month ago TopMedia.js 1 month ago TopPerformingMedia.js 1 month ago TopUsers.js 1 month ago TruncatedTitle.js 1 month ago UpgradeNotice.js 1 month ago UpgradeToPro.js 1 month ago VideoModal.js 1 month ago WelcomeBanner.js 1 month ago
ChooseDate.js
135 lines
1 import React, { useRef, useState, useEffect } from 'react';
2 import { __ } from '@wordpress/i18n';
3 import { DatePicker, Input } from '@bsf/force-ui';
4 import { Calendar, Trash2, ChevronDown } from 'lucide-react';
5 import { format } from '../utils/dateUtils';
6
7 function parseToDate(value) {
8 if (!value) return null;
9 if (value instanceof Date) return isNaN(value.getTime()) ? null : value;
10 const d = new Date(String(value).replace(' ', 'T'));
11 return isNaN(d.getTime()) ? null : d;
12 }
13
14 export default function ChooseDate({
15 chosenDate,
16 onPickDate,
17 placeholder,
18 className = '',
19 size = 'md',
20 }) {
21 const [isOpen, setIsOpen] = useState(false);
22 const [dropdownStyle, setDropdownStyle] = useState({});
23 const wrapperRef = useRef(null);
24 const triggerRef = useRef(null);
25
26 const selectedDate = parseToDate(chosenDate);
27
28 useEffect(() => {
29 function handleClickOutside(e) {
30 if (wrapperRef.current && !wrapperRef.current.contains(e.target)) {
31 setIsOpen(false);
32 }
33 }
34 if (isOpen) {
35 document.addEventListener('mousedown', handleClickOutside);
36 }
37 return () => document.removeEventListener('mousedown', handleClickOutside);
38 }, [isOpen]);
39
40 const displayValue = selectedDate
41 ? format(selectedDate, 'MMM dd, yyyy')
42 : '';
43
44 const handleDateSelect = (date) => {
45 if (!date) return;
46 const d = date instanceof Date ? date : new Date(date);
47 if (isNaN(d.getTime())) return;
48 const year = d.getFullYear();
49 const month = String(d.getMonth() + 1).padStart(2, '0');
50 const day = String(d.getDate()).padStart(2, '0');
51 if (typeof onPickDate === 'function') {
52 onPickDate(`${year}-${month}-${day}`);
53 }
54 setIsOpen(false);
55 };
56
57 const clearDate = (e) => {
58 e.preventDefault();
59 e.stopPropagation();
60 if (typeof onPickDate === 'function') {
61 onPickDate('');
62 }
63 setIsOpen(false);
64 };
65
66 return (
67 <div ref={wrapperRef} className={`relative ${className}`}>
68 <div className="flex items-center gap-1">
69 <div
70 className="flex-1 cursor-pointer"
71 ref={triggerRef}
72 onClick={() => {
73 if (!isOpen && triggerRef.current) {
74 const rect = triggerRef.current.getBoundingClientRect();
75 // DatePicker is ~340px tall; pad to 360 so we flip before the
76 // last row clips against the viewport.
77 const POPOVER_HEIGHT = 360;
78 const GAP = 4;
79 const spaceBelow = window.innerHeight - rect.bottom;
80 const spaceAbove = rect.top;
81 const flipUp =
82 spaceBelow < POPOVER_HEIGHT + GAP &&
83 spaceAbove > spaceBelow;
84 const style = {
85 position: 'fixed',
86 left: rect.left,
87 zIndex: 99999,
88 };
89 if (flipUp) {
90 style.bottom = window.innerHeight - rect.top + GAP;
91 } else {
92 style.top = rect.bottom + GAP;
93 }
94 setDropdownStyle(style);
95 }
96 setIsOpen((prev) => !prev);
97 }}
98 >
99 <Input
100 size={size}
101 value={displayValue}
102 readOnly
103 placeholder={placeholder || __('Select date', 'presto-player')}
104 prefix={<Calendar size={16} />}
105 suffix={<ChevronDown size={16} />}
106 className="cursor-pointer"
107 />
108 </div>
109 {selectedDate && (
110 <button
111 type="button"
112 onClick={clearDate}
113 className="p-1.5 text-gray-400 hover:text-red-500 transition-colors border-0 bg-transparent outline-none shrink-0"
114 title={__('Clear Date', 'presto-player')}
115 aria-label={__('Clear Date', 'presto-player')}
116 >
117 <Trash2 size={16} aria-hidden="true" />
118 </button>
119 )}
120 </div>
121
122 {isOpen && (
123 <div style={dropdownStyle} className="rounded-lg shadow-lg">
124 <DatePicker
125 selectionType="single"
126 selected={selectedDate}
127 onDateSelect={handleDateSelect}
128 isFooter={false}
129 />
130 </div>
131 )}
132 </div>
133 );
134 }
135