diff --git a/README.md b/README.md index 2a6bfa3a..78149e12 100644 --- a/README.md +++ b/README.md @@ -229,16 +229,13 @@ Contributions are what make the open source community such an amazing place to b 2. On the upper right, click "Develop" => "Build App". 3. On "OAuth", select "Create". 4. Name your App. -5. Choose "Account-level app" as the app type. +5. Choose "User-managed app" as the app type. 6. De-select the option to publish the app on the Zoom App Marketplace. 7. Click "Create". 8. Now copy the Client ID and Client Secret to your .env file into the `ZOOM_CLIENT_ID` and `ZOOM_CLIENT_SECRET` fields. 9. Set the Redirect URL for OAuth `/api/integrations/zoomvideo/callback` replacing CALENDSO URL with the URI at which your application runs. 10. Also add the redirect URL given above as a whitelist URL and enable "Subdomain check". Make sure, it says "saved" below the form. -11. You don't need to provide basic information about your app. Instead click at "Scopes" and then at "+ Add Scopes". Search for and check the following scopes: - 1. account:write:admin - 2. meeting:write:admin - 3. user:write:admin +11. You don't need to provide basic information about your app. Instead click at "Scopes" and then at "+ Add Scopes". On the left, click the category "Meeting" and check the scope `meeting:write`. 12. Click "Done". 13. You're good to go. Now you can easily add your Zoom integration in the Calendso settings. diff --git a/components/Dialog.tsx b/components/Dialog.tsx new file mode 100644 index 00000000..08140d72 --- /dev/null +++ b/components/Dialog.tsx @@ -0,0 +1,38 @@ +import React from "react"; +import * as DialogPrimitive from "@radix-ui/react-dialog"; + +export function Dialog({ children, ...props }) { + return ( + + + {children} + + ); +} + +export const DialogContent = React.forwardRef(({ children, ...props }, forwardedRef) => ( + + {children} + +)); + +export function DialogHeader({ title, subtitle }: { title: string; subtitle: string }) { + return ( +
+ +
+

{subtitle}

+
+
+ ); +} + +DialogContent.displayName = "DialogContent"; + +export const DialogTrigger = DialogPrimitive.Trigger; +export const DialogClose = DialogPrimitive.Close; diff --git a/components/Loader.tsx b/components/Loader.tsx index b66dfe18..b6c49c94 100644 --- a/components/Loader.tsx +++ b/components/Loader.tsx @@ -1,3 +1,7 @@ -export default function Loader(){ - return
-} \ No newline at end of file +export default function Loader() { + return ( +
+ +
+ ); +} diff --git a/components/Modal.tsx b/components/Modal.tsx index 12232876..ed4fbbe5 100644 --- a/components/Modal.tsx +++ b/components/Modal.tsx @@ -5,7 +5,7 @@ import { CheckIcon } from '@heroicons/react/outline' export default function Modal(props) { return ( - +
- + {/* This element is to trick the browser into centering the modal contents. */} diff --git a/components/Settings.tsx b/components/Settings.tsx index 6c182c75..b9f56c62 100644 --- a/components/Settings.tsx +++ b/components/Settings.tsx @@ -1,10 +1,7 @@ import Link from "next/link"; import { CreditCardIcon, UserIcon, CodeIcon, KeyIcon, UserGroupIcon } from "@heroicons/react/solid"; import { useRouter } from "next/router"; - -function classNames(...classes) { - return classes.filter(Boolean).join(" "); -} +import classNames from "@lib/classNames"; export default function SettingsShell(props) { const router = useRouter(); @@ -38,7 +35,7 @@ export default function SettingsShell(props) { ]; return ( -
+
+
-
{props.children}
+
{props.children}
); } diff --git a/components/Shell.tsx b/components/Shell.tsx index bce52a41..e4af877a 100644 --- a/components/Shell.tsx +++ b/components/Shell.tsx @@ -16,13 +16,11 @@ import { LinkIcon, } from "@heroicons/react/solid"; import Logo from "./Logo"; - -function classNames(...classes) { - return classes.filter(Boolean).join(" "); -} +import classNames from "@lib/classNames"; export default function Shell(props) { const router = useRouter(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars const [session, loading] = useSession(); const telemetry = useTelemetry(); @@ -46,7 +44,7 @@ export default function Shell(props) { current: router.pathname.startsWith("/availability"), }, { - name: "Integrations", + name: "App Store", href: "/integrations", icon: PuzzleIcon, current: router.pathname.startsWith("/integrations"), @@ -70,117 +68,121 @@ export default function Shell(props) { } return session ? ( -
- {/* Static sidebar for desktop */} -
-
- {/* Sidebar component, swap this element with another sidebar if you like */} -
-
- - - - - - +
+
+ +
-
-
- {/* show top navigation for md and smaller (tablet and phones) */} - - -
-
-
-
-

{props.heading}

-

{props.subtitle}

-
-
{props.CTA}
-
-
{props.children}
- - {/* show bottom navigation for md and smaller (tablet and phones) */} - +
+
+
+

{props.heading}

+

{props.subtitle}

+
+
{props.CTA}
+
+
{props.children}
- {/* add padding to content for mobile navigation*/} -
-
-
+ {/* show bottom navigation for md and smaller (tablet and phones) */} + + + {/* add padding to content for mobile navigation*/} +
+
+ +
-
+ ) : null; } @@ -210,7 +212,7 @@ function UserDropdown({ session, small, bottom }: { session: any; small?: boolea {session.user.name} - {session.user.username} + /{session.user.username} )} diff --git a/components/Tooltip.tsx b/components/Tooltip.tsx new file mode 100644 index 00000000..dfab8cdd --- /dev/null +++ b/components/Tooltip.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import * as TooltipPrimitive from "@radix-ui/react-tooltip"; +import { Slot } from "@radix-ui/react-slot"; + +export function Tooltip({ + children, + content, + open, + defaultOpen, + onOpenChange, + ...props +}: { + [x: string]: any; + children: React.ReactNode; + content: React.ReactNode; + open: boolean; + defaultOpen: boolean; + onOpenChange: (open: boolean) => void; +}) { + return ( + + {children} + + {content} + + + ); +} diff --git a/components/booking/AvailableTimes.tsx b/components/booking/AvailableTimes.tsx index e2d6af3e..4f7a5fd4 100644 --- a/components/booking/AvailableTimes.tsx +++ b/components/booking/AvailableTimes.tsx @@ -2,6 +2,8 @@ import Link from "next/link"; import { useRouter } from "next/router"; import Slots from "./Slots"; import { ExclamationIcon } from "@heroicons/react/solid"; +import React from "react"; +import Loader from "@components/Loader"; const AvailableTimes = ({ date, @@ -25,7 +27,7 @@ const AvailableTimes = ({ }); return ( -
+
{date.format("dddd DD MMMM YYYY")}
@@ -37,7 +39,7 @@ const AvailableTimes = ({ `/${user.username}/book?date=${slot.utc().format()}&type=${eventTypeId}` + (rescheduleUid ? "&rescheduleUid=" + rescheduleUid : "") }> - + {slot.format(timeFormat)} @@ -49,7 +51,7 @@ const AvailableTimes = ({
)} - {!isFullyBooked && slots.length === 0 && !hasErrors &&
} + {!isFullyBooked && slots.length === 0 && !hasErrors && } {hasErrors && (
diff --git a/components/booking/DatePicker.tsx b/components/booking/DatePicker.tsx index c6a49fa0..41a4ab94 100644 --- a/components/booking/DatePicker.tsx +++ b/components/booking/DatePicker.tsx @@ -147,12 +147,14 @@ const DatePicker = ({ onClick={() => setSelectedDate(inviteeDate.date(day))} disabled={isDisabled(day)} className={ - "text-center w-10 h-10 rounded-full mx-auto" + - (isDisabled(day) ? " text-gray-400 font-light" : " text-blue-600 font-medium") + + "text-center w-10 h-10 mx-auto hover:border hover:border-black dark:hover:border-white" + + (isDisabled(day) + ? " text-gray-400 font-light hover:border-0 cursor-default" + : " dark:text-white text-primary-500 font-medium") + (selectedDate && selectedDate.isSame(inviteeDate.date(day), "day") - ? " bg-blue-600 text-white-important" + ? " bg-black text-white-important" : !isDisabled(day) - ? " bg-blue-50 dark:bg-gray-900 dark:bg-opacity-30" + ? " bg-gray-100 dark:bg-black dark:bg-opacity-30" : "") }> {day} @@ -164,26 +166,34 @@ const DatePicker = ({ return selectedMonth ? (
- {dayjs().month(selectedMonth).format("MMMM YYYY")} + + {dayjs().month(selectedMonth).format("MMMM")} + + {dayjs().month(selectedMonth).format("YYYY")} -
+
-
-
+
{["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] .sort((a, b) => (weekStart.startsWith(a) ? -1 : weekStart.startsWith(b) ? 1 : 0)) .map((weekDay) => ( diff --git a/components/booking/TimeOptions.tsx b/components/booking/TimeOptions.tsx index 52023e79..9e51b6ae 100644 --- a/components/booking/TimeOptions.tsx +++ b/components/booking/TimeOptions.tsx @@ -2,10 +2,7 @@ import { Switch } from "@headlessui/react"; import TimezoneSelect from "react-timezone-select"; import { useEffect, useState } from "react"; import { is24h, timeZone } from "../../lib/clock"; - -function classNames(...classes) { - return classes.filter(Boolean).join(" "); -} +import classNames from "@lib/classNames"; const TimeOptions = (props) => { const [selectedTimeZone, setSelectedTimeZone] = useState(""); @@ -28,7 +25,7 @@ const TimeOptions = (props) => { return ( selectedTimeZone !== "" && ( -
+
Time Options
@@ -40,7 +37,7 @@ const TimeOptions = (props) => { checked={is24hClock} onChange={setIs24hClock} className={classNames( - is24hClock ? "bg-blue-600" : "dark:bg-gray-600 bg-gray-200", + is24hClock ? "bg-black" : "dark:bg-gray-600 bg-gray-200", "relative inline-flex flex-shrink-0 h-5 w-8 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black" )}> Use setting diff --git a/components/team/EditTeamModal.tsx b/components/team/EditTeamModal.tsx index d6991a1e..c5e15c6f 100644 --- a/components/team/EditTeamModal.tsx +++ b/components/team/EditTeamModal.tsx @@ -32,9 +32,9 @@ export default function EditTeamModal(props) { }).then(loadMembers); } - return (
+ return (
- + diff --git a/components/team/MemberInvitationModal.tsx b/components/team/MemberInvitationModal.tsx index f355abe1..6c916baa 100644 --- a/components/team/MemberInvitationModal.tsx +++ b/components/team/MemberInvitationModal.tsx @@ -40,12 +40,12 @@ export default function MemberInvitationModal(props) { return (
- +