diff --git a/package-lock.json b/package-lock.json index b8ea6905..f6d936fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "firebase": "^9.6.9", "framer-motion": "^6.3.0", "react": "^17.0.2", + "react-datepicker": "^4.7.0", "react-dom": "^17.0.2", "react-firebase-hooks": "^5.0.3", "react-hot-toast": "^2.2.0", @@ -35,6 +36,7 @@ "web-vitals": "^2.1.4" }, "devDependencies": { + "@types/react-datepicker": "^4.4.1", "@typescript-eslint/eslint-plugin": "^5.16.0", "@typescript-eslint/parser": "^5.16.0", "autoprefixer": "^10.4.4", @@ -3386,6 +3388,15 @@ "node": ">= 8" } }, + "node_modules/@popperjs/core": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz", + "integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -4256,6 +4267,18 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-datepicker": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@types/react-datepicker/-/react-datepicker-4.4.1.tgz", + "integrity": "sha512-M8+hzwj+bpuwxC82z35NxkD3sqMl/vVXTs6xjPAsYqjucVXFpY1DK6ETKgICZE7YpuPYpf2OYF2OVZ5E7R42rA==", + "dev": true, + "dependencies": { + "@popperjs/core": "^2.9.2", + "@types/react": "*", + "date-fns": "^2.0.1", + "react-popper": "^2.2.5" + } + }, "node_modules/@types/react-dom": { "version": "17.0.14", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.14.tgz", @@ -14542,6 +14565,23 @@ "node": ">=14" } }, + "node_modules/react-datepicker": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-4.7.0.tgz", + "integrity": "sha512-FS8KgbwqpxmJBv/bUdA42MYqYZa+fEYcpc746DZiHvVE2nhjrW/dg7c5B5fIUuI8gZET6FOzuDgezNcj568Czw==", + "dependencies": { + "@popperjs/core": "^2.9.2", + "classnames": "^2.2.6", + "date-fns": "^2.24.0", + "prop-types": "^15.7.2", + "react-onclickoutside": "^6.12.0", + "react-popper": "^2.2.5" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17", + "react-dom": "^16.9.0 || ^17" + } + }, "node_modules/react-dev-utils": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz", @@ -14677,6 +14717,11 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz", "integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==" }, + "node_modules/react-fast-compare": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", + "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + }, "node_modules/react-firebase-hooks": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/react-firebase-hooks/-/react-firebase-hooks-5.0.3.tgz", @@ -14719,6 +14764,33 @@ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, + "node_modules/react-onclickoutside": { + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.12.1.tgz", + "integrity": "sha512-a5Q7CkWznBRUWPmocCvE8b6lEYw1s6+opp/60dCunhO+G6E4tDTO2Sd2jKE+leEnnrLAE2Wj5DlDHNqj5wPv1Q==", + "funding": { + "type": "individual", + "url": "https://github.com/Pomax/react-onclickoutside/blob/master/FUNDING.md" + }, + "peerDependencies": { + "react": "^15.5.x || ^16.x || ^17.x", + "react-dom": "^15.5.x || ^16.x || ^17.x" + } + }, + "node_modules/react-popper": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", + "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==", + "dependencies": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + }, + "peerDependencies": { + "@popperjs/core": "^2.0.0", + "react": "^16.8.0 || ^17 || ^18", + "react-dom": "^16.8.0 || ^17 || ^18" + } + }, "node_modules/react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", @@ -16856,6 +16928,14 @@ "makeerror": "1.0.12" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/watchpack": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", @@ -20126,6 +20206,11 @@ } } }, + "@popperjs/core": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz", + "integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==" + }, "@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -20803,6 +20888,18 @@ "csstype": "^3.0.2" } }, + "@types/react-datepicker": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@types/react-datepicker/-/react-datepicker-4.4.1.tgz", + "integrity": "sha512-M8+hzwj+bpuwxC82z35NxkD3sqMl/vVXTs6xjPAsYqjucVXFpY1DK6ETKgICZE7YpuPYpf2OYF2OVZ5E7R42rA==", + "dev": true, + "requires": { + "@popperjs/core": "^2.9.2", + "@types/react": "*", + "date-fns": "^2.0.1", + "react-popper": "^2.2.5" + } + }, "@types/react-dom": { "version": "17.0.14", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.14.tgz", @@ -28148,6 +28245,19 @@ "whatwg-fetch": "^3.6.2" } }, + "react-datepicker": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-4.7.0.tgz", + "integrity": "sha512-FS8KgbwqpxmJBv/bUdA42MYqYZa+fEYcpc746DZiHvVE2nhjrW/dg7c5B5fIUuI8gZET6FOzuDgezNcj568Czw==", + "requires": { + "@popperjs/core": "^2.9.2", + "classnames": "^2.2.6", + "date-fns": "^2.24.0", + "prop-types": "^15.7.2", + "react-onclickoutside": "^6.12.0", + "react-popper": "^2.2.5" + } + }, "react-dev-utils": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz", @@ -28249,6 +28359,11 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz", "integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==" }, + "react-fast-compare": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", + "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + }, "react-firebase-hooks": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/react-firebase-hooks/-/react-firebase-hooks-5.0.3.tgz", @@ -28281,6 +28396,21 @@ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, + "react-onclickoutside": { + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.12.1.tgz", + "integrity": "sha512-a5Q7CkWznBRUWPmocCvE8b6lEYw1s6+opp/60dCunhO+G6E4tDTO2Sd2jKE+leEnnrLAE2Wj5DlDHNqj5wPv1Q==", + "requires": {} + }, + "react-popper": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", + "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==", + "requires": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + } + }, "react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", @@ -29876,6 +30006,14 @@ "makeerror": "1.0.12" } }, + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "^1.0.0" + } + }, "watchpack": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", diff --git a/package.json b/package.json index 6ab1a105..2837203a 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "firebase": "^9.6.9", "framer-motion": "^6.3.0", "react": "^17.0.2", + "react-datepicker": "^4.7.0", "react-dom": "^17.0.2", "react-firebase-hooks": "^5.0.3", "react-hot-toast": "^2.2.0", @@ -58,6 +59,7 @@ ] }, "devDependencies": { + "@types/react-datepicker": "^4.4.1", "@typescript-eslint/eslint-plugin": "^5.16.0", "@typescript-eslint/parser": "^5.16.0", "autoprefixer": "^10.4.4", diff --git a/src/Components/BurgerMenu/BurgerMenu.tsx b/src/Components/BurgerMenu/BurgerMenu.tsx index 4038244b..9a5c5e01 100644 --- a/src/Components/BurgerMenu/BurgerMenu.tsx +++ b/src/Components/BurgerMenu/BurgerMenu.tsx @@ -16,7 +16,7 @@ const BurgerMenu = ({ isOpen, children }: BurgerMenuProps) => { initial="closed" variants={variants} id="burger_menu" - className="fixed shadow-md left-0 z-10 flex flex-col items-center justify-center w-screen top-20 bg-zinc-100 md:hidden" + className="fixed pb-2 shadow-md left-0 z-10 flex flex-col items-center justify-center w-screen top-20 bg-zinc-100 lg:hidden" > {children} </motion.div> diff --git a/src/Components/DataCard/DataCard.tsx b/src/Components/DataCard/DataCard.tsx index 4194bde9..559eb49a 100644 --- a/src/Components/DataCard/DataCard.tsx +++ b/src/Components/DataCard/DataCard.tsx @@ -5,7 +5,7 @@ type Props = { export default function DataCard({ title, value }: Props) { return ( - <div className="px-6 m-1 py-2 w-[200px] bg-white rounded-lg border border-gray-200 shadow-md"> + <div className="px-6 m-1 py-2 w-[200px] bg-white rounded-lg border border-zinc-200 shadow-md"> <h3 className="font-semibold mb-1">{title}</h3> {value} </div> diff --git a/src/Components/DatePicker/DatePicker.tsx b/src/Components/DatePicker/DatePicker.tsx deleted file mode 100644 index 7e644fef..00000000 --- a/src/Components/DatePicker/DatePicker.tsx +++ /dev/null @@ -1,297 +0,0 @@ -import { useState, useEffect, useRef } from 'react'; -import { - format, - subMonths, - addMonths, - subYears, - addYears, - isEqual, - getDaysInMonth, - getDay, -} from 'date-fns'; -import { useCloseComponent } from '../../Hooks/useCloseComponent'; - -type DatepickerType = 'date' | 'month' | 'year'; - -type DatepickerProps = { - selectedDate: Date; - setSelectedDate: (date: Date) => void; -}; - -const DatePicker = ({ selectedDate, setSelectedDate }: DatepickerProps) => { - const DAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; - const [dayCount, setDayCount] = useState<Array<number>>([]); - const [blankDays, setBlankDays] = useState<Array<number>>([]); - const [showDatepicker, setShowDatepicker] = useState(false); - const [datepickerHeaderDate, setDatepickerHeaderDate] = useState(new Date()); - const [type, setType] = useState<DatepickerType>('date'); - const wrapperRef = useRef<HTMLDivElement>(null); - - useCloseComponent(wrapperRef, () => setShowDatepicker(false)); - - const decrement = () => { - switch (type) { - case 'date': - setDatepickerHeaderDate((prev) => subMonths(prev, 1)); - break; - case 'month': - setDatepickerHeaderDate((prev) => subYears(prev, 1)); - break; - case 'year': - setDatepickerHeaderDate((prev) => subMonths(prev, 1)); - break; - } - }; - - const increment = () => { - switch (type) { - case 'date': - setDatepickerHeaderDate((prev) => addMonths(prev, 1)); - break; - case 'month': - setDatepickerHeaderDate((prev) => addYears(prev, 1)); - break; - case 'year': - setDatepickerHeaderDate((prev) => subMonths(prev, 1)); - break; - } - }; - - const isToday = (date: number) => - isEqual( - new Date(selectedDate.getFullYear(), selectedDate.getMonth(), date), - selectedDate - ); - - const setDateValue = (date: number) => () => { - setSelectedDate( - new Date( - datepickerHeaderDate.getFullYear(), - datepickerHeaderDate.getMonth(), - date, - new Date().getHours() - ) - ); - setShowDatepicker(false); - }; - - const getDayCount = (date: Date) => { - const daysInMonth = getDaysInMonth(date); - - const dayOfWeek = getDay(new Date(date.getFullYear(), date.getMonth(), 1)); - const blankdaysArray: Array<number> = []; - for (let i = 1; i <= dayOfWeek; i++) { - blankdaysArray.push(i); - } - - const daysArray: Array<number> = []; - for (let i = 1; i <= daysInMonth; i++) { - daysArray.push(i); - } - - setBlankDays(blankdaysArray); - setDayCount(daysArray); - }; - - const isSelectedMonth = (month: number) => - isEqual( - new Date(selectedDate.getFullYear(), month, selectedDate.getDate()), - selectedDate - ); - - const setMonthValue = (month: number) => () => { - setDatepickerHeaderDate( - new Date( - datepickerHeaderDate.getFullYear(), - month, - datepickerHeaderDate.getDate() - ) - ); - setType('date'); - }; - - const toggleDatepicker = () => { - setShowDatepicker((prev) => !prev); - }; - - const showMonthPicker = () => setType('month'); - - const showYearPicker = () => setType('date'); - - useEffect(() => { - getDayCount(datepickerHeaderDate); - }, [datepickerHeaderDate]); - - return ( - <div ref={wrapperRef} className="relative z-1 w-full md:w-[250px]"> - <input type="hidden" name="date" /> - <input - type="text" - readOnly - className="w-full py-3 pl-4 pr-10 font-medium leading-none rounded-lg shadow-sm cursor-pointer focus:outline-none focus:shadow-outline text-zinc-600" - placeholder="Select date" - value={format(selectedDate, 'yyyy-MM-dd')} - onClick={toggleDatepicker} - /> - <div - className="absolute top-0 right-0 px-3 py-2 cursor-pointer" - onClick={toggleDatepicker} - > - <svg - className="w-6 h-6 text-zinc-400" - fill="none" - viewBox="0 0 24 24" - stroke="currentColor" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" - /> - </svg> - </div> - {showDatepicker && ( - <div - className="absolute top-0 left-0 right-0 z-20 p-4 mx-auto mt-12 bg-white rounded-lg shadow" - style={{ width: '17rem' }} - > - <div className="flex items-center justify-between mb-2"> - <div> - <button - type="button" - className="inline-flex p-1 transition duration-100 ease-in-out rounded-full cursor-pointer hover:bg-zinc-200" - onClick={decrement} - > - <svg - className="inline-flex w-6 h-6 text-zinc-500" - fill="none" - viewBox="0 0 24 24" - stroke="currentColor" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M15 19l-7-7 7-7" - /> - </svg> - </button> - </div> - {type === 'date' && ( - <div - onClick={showMonthPicker} - className="flex-grow p-1 text-lg font-bold rounded-lg cursor-pointer text-zinc-800 hover:bg-zinc-200" - > - <p className="text-center"> - {format(datepickerHeaderDate, 'MMMM')} - </p> - </div> - )} - <div - onClick={showYearPicker} - className="flex-grow p-1 text-lg font-bold rounded-lg cursor-pointer text-zinc-800 hover:bg-zinc-200" - > - <p className="text-center"> - {format(datepickerHeaderDate, 'yyyy')} - </p> - </div> - <div> - <button - type="button" - className="inline-flex p-1 transition duration-100 ease-in-out rounded-full cursor-pointer hover:bg-zinc-200" - onClick={increment} - > - <svg - className="inline-flex w-6 h-6 text-zinc-500" - fill="none" - viewBox="0 0 24 24" - stroke="currentColor" - > - <path - strokeLinecap="round" - strokeLinejoin="round" - strokeWidth={2} - d="M9 5l7 7-7 7" - /> - </svg> - </button> - </div> - </div> - {type === 'date' && ( - <> - <div className="flex flex-wrap mb-3 -mx-1"> - {DAYS.map((day, i) => ( - <div key={i} style={{ width: '14.26%' }} className="px-1"> - <div className="text-xs font-medium text-center text-zinc-800"> - {day} - </div> - </div> - ))} - </div> - <div className="flex flex-wrap -mx-1"> - {blankDays.map((_, i) => ( - <div - key={i} - style={{ width: '14.26%' }} - className="p-1 text-sm text-center border border-transparent" - ></div> - ))} - {dayCount.map((d, i) => ( - <div - key={i} - style={{ width: '14.26%' }} - className="px-1 mb-1" - > - <div - onClick={setDateValue(d)} - className={`cursor-pointer text-center text-sm rounded-full leading-loose transition ease-in-out duration-100 ${ - isToday(d) - ? 'bg-indigo-500 text-white' - : 'text-zinc-700 hover:bg-indigo-200' - }`} - > - {d} - </div> - </div> - ))} - </div> - </> - )} - {type === 'month' && ( - <div className="flex flex-wrap -mx-1"> - {Array(12) - .fill(null) - .map((_, i) => ( - <div - key={i} - onClick={setMonthValue(i)} - style={{ width: '25%' }} - > - <div - className={`cursor-pointer p-5 font-semibold text-center text-sm rounded-lg hover:bg-zinc-200 ${ - isSelectedMonth(i) - ? 'bg-indigo-500 text-white' - : 'text-zinc-700 hover:bg-indigo-200' - }`} - > - {format( - new Date( - datepickerHeaderDate.getFullYear(), - i, - datepickerHeaderDate.getDate() - ), - 'MMM' - )} - </div> - </div> - ))} - </div> - )} - </div> - )} - </div> - ); -}; - -export default DatePicker; diff --git a/src/Components/DatePicker/index.ts b/src/Components/DatePicker/index.ts deleted file mode 100644 index 7d981a22..00000000 --- a/src/Components/DatePicker/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from './DatePicker'; -export * from './DatePicker'; \ No newline at end of file diff --git a/src/Components/Navigation/Navigation.tsx b/src/Components/Navigation/Navigation.tsx index d028147a..219e9b4e 100644 --- a/src/Components/Navigation/Navigation.tsx +++ b/src/Components/Navigation/Navigation.tsx @@ -28,7 +28,7 @@ function Navigation() { <Logo /> {!loading && user ? ( <div className="flex md:space-x-4"> - <div className="hidden space-x-4 md:block"> + <div className="hidden space-x-4 lg:block"> <Link to={'/survey/create'}> <Button variant={ButtonVariant.FLAT}>Create Survey</Button> </Link> @@ -36,7 +36,7 @@ function Navigation() { <Button variant={ButtonVariant.FLAT}>My Surveys</Button> </Link> </div> - <div className="sm:flex justify-center items-center hidden"> + <div className="lg:flex justify-center items-center hidden"> <Menu as="div" className="relative inline-block text-left rounded-md" @@ -45,7 +45,7 @@ function Navigation() { title="Expand menu" className="flex w-full justify-center hover:bg-zinc-200 py-1 rounded-md px-4 font-medium" > - <p className="truncate items-center hidden justify-left sm:flex ml-4"> + <p className="truncate items-center hidden justify-left sm:flex ml-2"> {user.displayName} {user.photoURL && ( <img @@ -71,7 +71,7 @@ function Navigation() { <IconButton onClick={logoutDesktop} variant={IconButtonVariant.FLAT} - className="hover:bg-red-100 text-red-600" + className="hover:bg-red-100 text-red-600 w-40" icon={<LogoutIcon className="w-5 h-5" />} > Sign Out @@ -84,7 +84,7 @@ function Navigation() { </div> <MenuIcon onClick={() => setIsOpen(!isOpen)} - className="z-50 w-8 h-8 cursor-pointer md:hidden" + className="z-50 w-8 h-8 cursor-pointer lg:hidden" /> </div> ) : ( diff --git a/src/Pages/SurveyCreatePage/SurveyCreatePage.tsx b/src/Pages/SurveyCreatePage/SurveyCreatePage.tsx index 0016f0df..446bc2ec 100644 --- a/src/Pages/SurveyCreatePage/SurveyCreatePage.tsx +++ b/src/Pages/SurveyCreatePage/SurveyCreatePage.tsx @@ -10,8 +10,9 @@ import { useNavigate } from 'react-router-dom'; import useCopyToClipboard from '../../Hooks/useCopyToClipboard'; import { useDocumentTitle } from '../../Hooks/useDocumentTitle'; import Header from '../../Components/Header'; -import DatePicker from '../../Components/DatePicker'; import withAnimation from '../../HOC/withAnimation'; +import DatePicker from 'react-datepicker'; +import '../../datepicker.scss'; function SurveyCreatePage() { useDocumentTitle('Create Survey'); @@ -23,8 +24,6 @@ function SurveyCreatePage() { const navigate = useNavigate(); const [, copy] = useCopyToClipboard(); - const [selectedStartDate, setSelectedStartDate] = useState(new Date()); - const [selectedEndDate, setSelectedEndDate] = useState(new Date()); const handleChangeTitle = (e: any) => { setTitle(e.target.value); @@ -37,17 +36,17 @@ function SurveyCreatePage() { }); }; - const [startDate, setStartDate] = useState(new Date()) as any; - const [endDate, setEndDate] = useState( - new Date().setMonth(startDate.getMonth() + 1) + const [startDate, setStartDate] = useState<Date | null>(new Date()); + const [endDate, setEndDate] = useState<Date | null>( + new Date().setDate(startDate!.getDate() + 1) as any ); useEffect(() => { - if (startDate > endDate) setStartDate(endDate); + if (startDate! > endDate!) setStartDate(endDate); }, [endDate]); useEffect(() => { - if (startDate > endDate) setEndDate(startDate); + if (startDate! > endDate!) setEndDate(startDate); }, [startDate]); const createSurvey = async () => { @@ -57,8 +56,8 @@ function SurveyCreatePage() { title, pack, creatorId: user?.uid, - startDate: selectedStartDate, - endDate: selectedEndDate, + startDate, + endDate, }); const domain = window.location.hostname === 'localhost' ? 'http://' : 'https://'; @@ -73,6 +72,20 @@ function SurveyCreatePage() { setButtonDisable(false); }; + const filterPassedTime = (time: string | number | Date) => { + const currentDate = new Date(); + const selectedDate = new Date(time); + + return currentDate.getTime() < selectedDate.getTime(); + }; + + const filterPassedSelectedTime = (time: string | number | Date) => { + const currentDate = startDate; + const selectedDate = new Date(time); + + return currentDate!.getTime() < selectedDate.getTime(); + }; + return ( <div className="container px-4 m-auto text-center md:px-8"> <Header>Create new survey</Header> @@ -87,14 +100,39 @@ function SurveyCreatePage() { <label className="block mt-10 mb-4 font-semibold text-left"> Select duration of survey </label> - <div className="flex flex-col items-center justify-center space-y-4 md:space-y-0 md:space-x-8 md:flex-row"> + <div className="flex flex-col items-center justify-center space-y-4 md:space-y-0 md:flex-row"> <DatePicker - selectedDate={selectedStartDate} - setSelectedDate={setSelectedStartDate} + className="w-full md:w-52 block text-center mr-auto py-3 px-4 font-medium leading-none rounded-lg shadow-sm cursor-pointer focus:outline-none focus:shadow-outline text-zinc-600" + selected={startDate} + onChange={(date) => setStartDate(date)} + calendarStartDay={1} + dateFormat="dd/MM/yyyy HH:mm" + timeFormat="HH:mm" + showTimeSelect + timeIntervals={5} + selectsStart + startDate={startDate} + endDate={endDate} + minDate={new Date()} + showPreviousMonths={false} + filterTime={filterPassedTime} /> + <p>to</p> <DatePicker - selectedDate={selectedEndDate} - setSelectedDate={setSelectedEndDate} + className="w-full md:w-52 text-center block py-3 ml-auto px-4 font-medium leading-none rounded-lg shadow-sm cursor-pointer focus:outline-none focus:shadow-outline text-zinc-600" + selected={endDate} + onChange={(date) => setEndDate(date)} + calendarStartDay={1} + dateFormat="dd/MM/yyyy HH:mm" + timeFormat="HH:mm" + showTimeSelect + timeIntervals={5} + selectsEnd + startDate={startDate} + endDate={endDate} + minDate={startDate} + showPreviousMonths={false} + filterTime={filterPassedSelectedTime} /> </div> diff --git a/src/Pages/SurveyPage/SurveyPage.tsx b/src/Pages/SurveyPage/SurveyPage.tsx index f381c5b9..dd64acc6 100644 --- a/src/Pages/SurveyPage/SurveyPage.tsx +++ b/src/Pages/SurveyPage/SurveyPage.tsx @@ -38,6 +38,15 @@ function SurveyPage() { return; } + if ( + surveyData.data()?.startDate.toDate().toISOString() > + new Date().toISOString() + ) { + toast.error('Survey is not opened yet'); + navigate('/'); + return; + } + if ( surveyData.data()?.endDate.toDate().toISOString() < new Date().toISOString() diff --git a/src/datepicker.scss b/src/datepicker.scss new file mode 100644 index 00000000..8de489f8 --- /dev/null +++ b/src/datepicker.scss @@ -0,0 +1,94 @@ +@tailwind components; +@tailwind utilities; + +@import 'node_modules/react-datepicker/src/stylesheets/datepicker.scss'; + +.react-datepicker { + @apply rounded-md shadow-md border-none font-sans; +} +.react-datepicker-popper, +.react-datepicker__month-container { + @apply rounded-md border-none; +} +.react-datepicker > * { + @apply bg-white text-zinc-900; +} + +.react-datepicker__header { + @apply bg-white rounded-md border-none; +} + +.react-datepicker__day, +.react-datepicker__month, +.react-datepicker__year, +.react-datepicker__day--weekend { + @apply bg-white text-zinc-900; +} + +.react-datepicker-time__input:focus-visible { + outline: none; +} + +.react-datepicker__triangle { + display: none; +} + +input[type='time']::-webkit-calendar-picker-indicator { + background: none; + display: none; +} + +.react-datepicker input[type='time'] { + margin-right: 5px; +} + +.react-datepicker__time-container + .react-datepicker__time + .react-datepicker__time-box + ul.react-datepicker__time-list + li.react-datepicker__time-list-item--selected { + @apply bg-indigo-200 text-indigo-900; +} + +.react-datepicker__time-container + .react-datepicker__time + .react-datepicker__time-box + ul.react-datepicker__time-list + li.react-datepicker__time-list-item--selected:hover { + @apply bg-indigo-200 text-indigo-900; +} + +.react-datepicker__day--selected { + @apply bg-indigo-500; +} + +.react-datepicker__day:hover { + @apply bg-indigo-200 text-indigo-900; +} + +.react-datepicker__day--in-range, +.react-datepicker__day--in-range:hover, +.react-datepicker__day--in-selecting-range, +.react-datepicker__day--in-selecting-range:not(.react-datepicker__day--in-range, .react-datepicker__month-text--in-range, .react-datepicker__month-text--quarter-in-range, .react-datepicker__year-text--in-range), +.react-datepicker__day--in-selecting-range:hover, +.react-datepicker__day--range-end, +.react-datepicker__day--range-end:hover, +.react-datepicker__day--selecting-range-end, +.react-datepicker__day--selecting-range-end:hover, +.react-datepicker__day--range-start, +.react-datepicker__day--range-start:hover { + @apply bg-indigo-100; +} + +.react-datepicker__day--disabled, +.react-datepicker__day--disabled:hover { + @apply bg-zinc-100 cursor-not-allowed; +} + +.react-datepicker__input-time-container { + @apply text-sm w-fit; +} + +.react-datepicker-time__input { + @apply p-1 rounded-md bg-zinc-100 border-none; +}