Merge branch 'main' of github.com:calendso/calendso

This commit is contained in:
Peer Richelsen 2021-08-03 10:12:17 +02:00
commit 0bc0119362
8 changed files with 189 additions and 48 deletions

View file

@ -171,10 +171,13 @@ const DatePicker = ({
<span className="w-1/2 text-gray-600 dark:text-white">
{dayjs().month(selectedMonth).format("MMMM YYYY")}
</span>
<div className="w-1/2 text-right">
<div className="w-1/2 text-right text-gray-600 dark:text-gray-400">
<button
onClick={decrementMonth}
className={"mr-4 " + (selectedMonth <= dayjs().tz(inviteeTimeZone).month() && "text-gray-400")}
className={
"mr-4 " +
(selectedMonth <= dayjs().tz(inviteeTimeZone).month() && "text-gray-400 dark:text-gray-600")
}
disabled={selectedMonth <= dayjs().tz(inviteeTimeZone).month()}>
<ChevronLeftIcon className="w-5 h-5" />
</button>

View file

@ -17,6 +17,7 @@
"@heroicons/react": "^1.0.1",
"@jitsu/sdk-js": "^2.0.1",
"@prisma/client": "^2.23.0",
"@radix-ui/react-collapsible": "^0.0.16",
"@tailwindcss/forms": "^0.2.1",
"async": "^3.2.0",
"bcryptjs": "^2.4.3",

View file

@ -4,6 +4,7 @@ import Head from "next/head";
import { ChevronDownIcon, ClockIcon, GlobeIcon } from "@heroicons/react/solid";
import { useRouter } from "next/router";
import dayjs, { Dayjs } from "dayjs";
import * as Collapsible from "@radix-ui/react-collapsible";
import prisma, { whereAndSelect } from "@lib/prisma";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "../../lib/telemetry";
@ -139,19 +140,21 @@ export default function Type(props): Type {
<ClockIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
{props.eventType.length} minutes
</p>
<button
onClick={() => setIsTimeOptionsOpen(!isTimeOptionsOpen)}
className="text-gray-500 mb-1 px-2 py-1 -ml-2">
<GlobeIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
{timeZone()}
<ChevronDownIcon className="inline-block w-4 h-4 ml-1 -mt-1" />
</button>
{isTimeOptionsOpen && (
<TimeOptions
onSelectTimeZone={handleSelectTimeZone}
onToggle24hClock={handleToggle24hClock}
/>
)}
<Collapsible.Root open={isTimeOptionsOpen} onOpenChange={setIsTimeOptionsOpen}>
<Collapsible.Trigger className="text-gray-500 mb-1 px-2 py-1 -ml-2">
<GlobeIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
{timeZone()}
<ChevronDownIcon className="inline-block w-4 h-4 ml-1 -mt-1" />
</Collapsible.Trigger>
<Collapsible.Content>
<TimeOptions
onSelectTimeZone={handleSelectTimeZone}
onToggle24hClock={handleToggle24hClock}
/>
</Collapsible.Content>
</Collapsible.Root>
<p className="dark:text-gray-200 text-gray-600 mt-3 mb-8">{props.eventType.description}</p>
</div>
<DatePicker

View file

@ -218,7 +218,9 @@ export default function Book(props: any): JSX.Element {
</div>
{locations.length > 1 && (
<div className="mb-4">
<span className="block text-sm font-medium text-gray-700">Location</span>
<span className="block text-sm font-medium dark:text-white text-gray-700">
Location
</span>
{locations.map((location) => (
<label key={location.type} className="block">
<input
@ -230,7 +232,9 @@ export default function Book(props: any): JSX.Element {
value={location.type}
checked={selectedLocation === location.type}
/>
<span className="text-sm ml-2">{locationLabels[location.type]}</span>
<span className="text-sm ml-2 dark:text-gray-500">
{locationLabels[location.type]}
</span>
</label>
))}
</div>

View file

@ -3,6 +3,8 @@ import prisma from "../../lib/prisma";
import { getSession, useSession } from "next-auth/client";
import Shell from "../../components/Shell";
import { useRouter } from "next/router";
import dayjs from "dayjs";
export default function Bookings({ bookings }) {
const [, loading] = useSession();
@ -37,6 +39,28 @@ export default function Bookings({ bookings }) {
<div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
<div className="shadow overflow-hidden border-b border-gray-200 sm:rounded-sm">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Person
</th>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Event
</th>
<th
scope="col"
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Date
</th>
<th scope="col" className="relative px-6 py-3">
<span className="sr-only">Actions</span>
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{bookings
.filter((booking) => !booking.confirmed && !booking.rejected)
@ -70,11 +94,14 @@ export default function Bookings({ bookings }) {
You and {booking.attendees[0].name}
</div>
</td>
{/* <td className="px-6 py-4 whitespace-nowrap">
<div className="text-sm text-gray-500">
{dayjs(booking.startTime).format("D MMMM YYYY HH:mm")}
</div>
</td> */}
<td className="px-6 py-4 whitespace-nowrap">
<div className="text-sm text-gray-900">
{dayjs(booking.startTime).format("D MMMM YYYY")}
</div>
<div className="text-sm text-gray-500">
{dayjs(booking.startTime).format("HH:mm")} - {dayjs(booking.endTime).format("HH:mm")}
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
{!booking.confirmed && !booking.rejected && (
<>
@ -137,7 +164,7 @@ export async function getServerSideProps(context) {
},
});
const bookings = await prisma.booking.findMany({
const b = await prisma.booking.findMany({
where: {
userId: user.id,
},
@ -149,11 +176,17 @@ export async function getServerSideProps(context) {
confirmed: true,
rejected: true,
id: true,
startTime: true,
endTime: true,
},
orderBy: {
startTime: "desc",
startTime: "asc",
},
});
const bookings = b.map(booking=>{
return ({...booking, startTime:booking.startTime.toISOString(), endTime:booking.endTime.toISOString(),})
});
return { props: { bookings } };
}

View file

@ -20,7 +20,7 @@ import {
PlusIcon,
UserIcon,
} from "@heroicons/react/solid";
import Loader from '@components/Loader';
import Loader from "@components/Loader";
export default function Availability({ user, types }) {
const [session, loading] = useSession();
@ -42,7 +42,7 @@ export default function Availability({ user, types }) {
// TODO: Add validation
const response = await fetch("/api/availability/eventtype", {
await fetch("/api/availability/eventtype", {
method: "POST",
body: JSON.stringify({
title: enteredTitle,
@ -66,7 +66,7 @@ export default function Availability({ user, types }) {
}
if (loading) {
return <Loader/>;
return <Loader />;
}
return (
@ -79,12 +79,14 @@ export default function Availability({ user, types }) {
heading="Event Types"
subtitle="Create events to share for people to book on your calendar."
CTA={
<button
onClick={toggleAddModal}
className="flex justify-center py-2 px-4 border border-transparent rounded-sm shadow-sm text-sm font-medium text-white bg-neutral-900 hover:bg-neutral-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900">
<PlusIcon className="w-5 h-5 mr-1" />
New event type
</button>
types.length !== 0 && (
<button
onClick={toggleAddModal}
className="flex justify-center py-2 px-4 border border-transparent rounded-sm shadow-sm text-sm font-medium text-white bg-neutral-900 hover:bg-neutral-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900">
<PlusIcon className="w-5 h-5 mr-1" />
New event type
</button>
)
}>
<div className="bg-white shadow overflow-hidden sm:rounded-sm">
<ul className="divide-y divide-neutral-200">
@ -261,9 +263,9 @@ export default function Availability({ user, types }) {
</ul>
</div>
{types.length === 0 && (
<div className="text-center max-w-lg mx-auto">
<div className="md:py-20">
<svg
className="mx-auto mb-4 w-32 h-32"
className="w-1/2 md:w-32 mx-auto block mb-4"
viewBox="0 0 132 132"
fill="none"
xmlns="http://www.w3.org/2000/svg">
@ -500,12 +502,19 @@ export default function Availability({ user, types }) {
</clipPath>
</defs>
</svg>
<h3 className="mt-2 text-xl font-bold text-neutral-900">Create your first event type</h3>
<p className="mt-1 text-md text-neutral-600">
Event types enable you to share links that show available times on your calendar and allow
people to make bookings with you.
</p>
<div className="text-center block md:max-w-screen-sm mx-auto">
<h3 className="mt-2 text-xl font-bold text-neutral-900">Create your first event type</h3>
<p className="mt-1 text-md text-neutral-600">
Event types enable you to share links that show available times on your calendar and allow
people to make bookings with you.
</p>
<button
onClick={toggleAddModal}
className="py-2 px-4 mt-6 border border-transparent rounded-sm shadow-sm text-sm font-medium text-white bg-neutral-900 hover:bg-neutral-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900">
<PlusIcon className="w-5 h-5 mr-1 inline" />
New event type
</button>
</div>
</div>
)}
{showAddModal && (

View file

@ -12,6 +12,11 @@ import TimezoneSelect from "react-timezone-select";
import { UsernameInput } from "../../components/ui/UsernameInput";
import ErrorAlert from "../../components/ui/alerts/Error";
const themeOptions = [
{ value: "light", label: "Light" },
{ value: "dark", label: "Dark" },
];
export default function Settings(props) {
const [successModalOpen, setSuccessModalOpen] = useState(false);
const usernameRef = useRef<HTMLInputElement>();
@ -19,18 +24,13 @@ export default function Settings(props) {
const descriptionRef = useRef<HTMLTextAreaElement>();
const avatarRef = useRef<HTMLInputElement>();
const hideBrandingRef = useRef<HTMLInputElement>();
const [selectedTheme, setSelectedTheme] = useState({ value: "" });
const [selectedTheme, setSelectedTheme] = useState({ value: props.user.theme });
const [selectedTimeZone, setSelectedTimeZone] = useState({ value: props.user.timeZone });
const [selectedWeekStartDay, setSelectedWeekStartDay] = useState({ value: "" });
const [selectedWeekStartDay, setSelectedWeekStartDay] = useState({ value: props.user.weekStart });
const [hasErrors, setHasErrors] = useState(false);
const [errorMessage, setErrorMessage] = useState("");
const themeOptions = [
{ value: "light", label: "Light" },
{ value: "dark", label: "Dark" },
];
useEffect(() => {
setSelectedTheme(
props.user.theme ? themeOptions.find((theme) => theme.value === props.user.theme) : null
@ -179,6 +179,7 @@ export default function Settings(props) {
id="theme"
isDisabled={!selectedTheme}
defaultValue={selectedTheme || themeOptions[0]}
value={selectedTheme || themeOptions[0]}
onChange={setSelectedTheme}
className="shadow-sm focus:ring-neutral-500 focus:border-neutral-500 mt-1 block w-full sm:text-sm border-gray-300 rounded-sm"
options={themeOptions}

View file

@ -753,6 +753,93 @@
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-2.26.0-23.9b816b3aa13cc270074f172f30d6eda8a8ce867d.tgz#cfdacfad3acc0f3bf1d7710aa8f3852fd85ac6d9"
integrity sha512-a0jIhLvw9rFh6nZTr5Y3uzP28I2xNDu3pqxANvwMNnmIoYr1wYEcO1pMXn/36BGXldDdAWMmAbhfloHA3IB8DA==
"@radix-ui/primitive@0.0.5":
version "0.0.5"
resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-0.0.5.tgz#8464fb4db04401bde72d36e27e05714080668d40"
integrity sha512-VeL6A5LpKYRJhDDj5tCTnzP3zm+FnvybsAkgBHQ4LUPPBnqRdWLoyKpZhlwFze/z22QHINaTIcE9Z/fTcrUR1g==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-collapsible@^0.0.16":
version "0.0.16"
resolved "https://registry.yarnpkg.com/@radix-ui/react-collapsible/-/react-collapsible-0.0.16.tgz#6a99068f70bb85a60f8cbd43f093bd3053ab61cc"
integrity sha512-kY9wojEbrpTge6sz3BZl1oXer2Szhi+MW60TSDf14mL6l8+e4ugp5y2ItGDjcW5B7AzL00dsMtqlxuAkhFjWxQ==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/primitive" "0.0.5"
"@radix-ui/react-compose-refs" "0.0.5"
"@radix-ui/react-context" "0.0.5"
"@radix-ui/react-id" "0.0.6"
"@radix-ui/react-polymorphic" "0.0.12"
"@radix-ui/react-presence" "0.0.14"
"@radix-ui/react-primitive" "0.0.14"
"@radix-ui/react-use-controllable-state" "0.0.6"
"@radix-ui/react-use-layout-effect" "0.0.5"
"@radix-ui/react-compose-refs@0.0.5":
version "0.0.5"
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-0.0.5.tgz#0f71f0de1dec341f30cebd420b6bc3d12a3037dd"
integrity sha512-O9mH9X/2EwuAEEoZXrU4alcrRbAhhZHGpIJ5bOH6rmRcokhaoWRBY1tOEe2lgHdb/bkKrY+viLi4Zq8Ju6/09Q==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-context@0.0.5":
version "0.0.5"
resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-0.0.5.tgz#7c15f46795d7765dabfaf6f9c53791ad28c521c2"
integrity sha512-bwrzAc0qc2EPepSTLBT4+93uCiI9wP78VSmPg2K+k71O/vpx7dPs0VqrewwCBNCHT54NIwaRr2hEsm2uqYi02A==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-id@0.0.6":
version "0.0.6"
resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-0.0.6.tgz#c4b27d11861805e91ac296e7758ab47e3947b65c"
integrity sha512-PzmraF34fYggsYvTIZVJ5S68WMp3aKUN3HkSmGnz4zn9zpRjkAbbg7Xn3ueQI3FQsLWKgyUfnpsmWFDndpcqYg==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-polymorphic@0.0.12":
version "0.0.12"
resolved "https://registry.yarnpkg.com/@radix-ui/react-polymorphic/-/react-polymorphic-0.0.12.tgz#bf4ae516669b68e059549538104d97322f7c876b"
integrity sha512-/GYNMicBnGzjD1d2fCAuzql1VeFrp8mqM3xfzT1kxhnV85TKdURO45jBfMgqo17XNXoNhWIAProUsCO4qFAAIg==
"@radix-ui/react-presence@0.0.14":
version "0.0.14"
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-0.0.14.tgz#6a86058bbbf46234dd8840dacd620b3ac5797025"
integrity sha512-ufof9B76DHXV0sC8H7Lswh2AepdJFG8qEtF32JWrbA9N1bl2Jnf9px76KsagyC0MA8crGEZO5A96wizGuSgGWQ==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-compose-refs" "0.0.5"
"@radix-ui/react-primitive@0.0.14":
version "0.0.14"
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-0.0.14.tgz#752a967cb05d4c5643634fe20274e7dc905d1cce"
integrity sha512-FYOWGCrxFpLdB534aWTwMK4Pjg8cxFb+745qWhPfI+cYi+aYUddJQD3ilRHHXxCBD72ve7/PufqeB7Y/QlKqgg==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-polymorphic" "0.0.12"
"@radix-ui/react-use-callback-ref@0.0.5":
version "0.0.5"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-0.0.5.tgz#fa8db050229cda573dfeeae213d74ef06f6130db"
integrity sha512-z1AI221vmq9f3vsDyrCsGLCatKagbM1YeCGdRMhMsUBzFFCaJ+Axyoe/ndVqW8wwsraGWr1zYVAhIEdlC0GvPg==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-use-controllable-state@0.0.6":
version "0.0.6"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-0.0.6.tgz#c4b16bc911a25889333388a684a04df937e5fec7"
integrity sha512-fBk4hUSKc4N7X/NAaifWYfKKfNuOB9xvj0MBQQYS5oOTNRgg4y8/Ax3jZ0adsplXDm7ix75sxqWm0nrvUoAjcw==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-use-callback-ref" "0.0.5"
"@radix-ui/react-use-layout-effect@0.0.5":
version "0.0.5"
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-0.0.5.tgz#cbbd059090edc765749da00d9f562a9abd43cbac"
integrity sha512-bNPW2JNOr/p2hXr0hfKKqrEy5deNSRF17sw3l9Z7qlEnvIbBtQ7iwY/wrxIz5P7XFyYGoXodIUDH5G8PEucE3A==
dependencies:
"@babel/runtime" "^7.13.10"
"@sinonjs/commons@^1.7.0":
version "1.8.3"
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d"