Add troubleshoot page & add loading spinners
This commit is contained in:
parent
43f899582f
commit
5c699f8471
8 changed files with 148 additions and 21 deletions
|
@ -28,7 +28,7 @@ export default function Availability(props) {
|
|||
const bufferMinsRef = useRef<HTMLInputElement>();
|
||||
|
||||
if (loading) {
|
||||
return <p className="text-gray-400">Loading...</p>;
|
||||
return <div className="loader"></div>;
|
||||
}
|
||||
|
||||
function toggleAddModal() {
|
||||
|
@ -169,22 +169,45 @@ export default function Availability(props) {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-white shadow rounded-lg">
|
||||
|
||||
<div className="flex">
|
||||
<div className="w-1/2 mr-2 bg-white shadow rounded-lg">
|
||||
<div className="px-4 py-5 sm:p-6">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-900">
|
||||
Change the start and end times of your day
|
||||
</h3>
|
||||
<div className="mt-2 max-w-xl text-sm text-gray-500">
|
||||
<p>
|
||||
Currently, your day is set to start at {convertMinsToHrsMins(props.user.startTime)} and end at {convertMinsToHrsMins(props.user.endTime)}.
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<button onClick={toggleChangeTimesModal} type="button" className="btn btn-primary">
|
||||
Change available times
|
||||
</button>
|
||||
</div>
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-900">
|
||||
Change the start and end times of your day
|
||||
</h3>
|
||||
<div className="mt-2 max-w-xl text-sm text-gray-500">
|
||||
<p>
|
||||
Currently, your day is set to start at {convertMinsToHrsMins(props.user.startTime)} and end at {convertMinsToHrsMins(props.user.endTime)}.
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<button onClick={toggleChangeTimesModal} type="button" className="btn btn-primary">
|
||||
Change available times
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-1/2 ml-2 bg-white shadow rounded-lg">
|
||||
<div className="px-4 py-5 sm:p-6">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-900">
|
||||
Something doesn't look right?
|
||||
</h3>
|
||||
<div className="mt-2 max-w-xl text-sm text-gray-500">
|
||||
<p>
|
||||
Troubleshoot your availability to explore why your times are showing as they are.
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<Link href="/availability/troubleshoot">
|
||||
<a className="btn btn-primary">
|
||||
Launch troubleshooter
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{showAddModal &&
|
||||
<div className="fixed z-10 inset-0 overflow-y-auto" aria-labelledby="modal-title" role="dialog" aria-modal="true">
|
||||
|
|
104
pages/availability/troubleshoot.tsx
Normal file
104
pages/availability/troubleshoot.tsx
Normal file
|
@ -0,0 +1,104 @@
|
|||
import Head from "next/head";
|
||||
import Shell from "../../components/Shell";
|
||||
import { getSession, useSession } from "next-auth/client";
|
||||
import { useState } from "react";
|
||||
import dayjs from "dayjs";
|
||||
import utc from "dayjs/plugin/utc";
|
||||
import { GetServerSideProps } from "next";
|
||||
import prisma from "@lib/prisma";
|
||||
dayjs.extend(utc);
|
||||
|
||||
export default function Troubleshoot({ user }) {
|
||||
const [session, loading] = useSession();
|
||||
const [availability, setAvailability] = useState([]);
|
||||
const [selectedDate, setSelectedDate] = useState(dayjs());
|
||||
|
||||
if (loading) {
|
||||
return <div className="loader"></div>;
|
||||
}
|
||||
|
||||
function convertMinsToHrsMins(mins) {
|
||||
let h = Math.floor(mins / 60);
|
||||
let m = mins % 60;
|
||||
h = h < 10 ? "0" + h : h;
|
||||
m = m < 10 ? "0" + m : m;
|
||||
return `${h}:${m}`;
|
||||
}
|
||||
|
||||
const fetchAvailability = (date) => {
|
||||
fetch(
|
||||
`/api/availability/${session.user.username}?dateFrom=${date
|
||||
.startOf("day")
|
||||
.utc()
|
||||
.startOf("day")
|
||||
.format()}&dateTo=${date.endOf("day").utc().endOf("day").format()}`
|
||||
)
|
||||
.then((res) => {
|
||||
return res.json();
|
||||
})
|
||||
.then((apires) => setAvailability(apires))
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
});
|
||||
};
|
||||
|
||||
fetchAvailability(selectedDate);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Head>
|
||||
<title>Troubleshoot | Calendso</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
<Shell heading="Troubleshoot">
|
||||
<div className="bg-white overflow-hidden shadow rounded-lg">
|
||||
<div className="px-4 py-5 sm:p-6">
|
||||
Here is an overview of your day on {selectedDate.format("D MMMM YYYY")}:
|
||||
<small className="block text-gray-400">Tip: Hover over the bold times for a full timestamp</small>
|
||||
<div className="mt-4 space-y-4">
|
||||
<div className="bg-gray-600 overflow-hidden rounded-lg">
|
||||
<div className="px-4 sm:px-6 py-2 text-white">
|
||||
Your day starts at {convertMinsToHrsMins(user.startTime)}
|
||||
</div>
|
||||
</div>
|
||||
{availability.map((slot) => (
|
||||
<div key={slot.start} className="bg-gray-100 overflow-hidden rounded-lg">
|
||||
<div className="px-4 py-5 sm:p-6 text-gray-600">
|
||||
Your calendar shows you as busy between <span className="font-medium text-gray-800" title={slot.start}>{dayjs(slot.start).format("HH:mm")}</span> and <span className="font-medium text-gray-800" title={slot.end}>{dayjs(slot.end).format("HH:mm")}</span> on {dayjs(slot.start).format("D MMMM YYYY")}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{availability.length === 0 && <div className="loader"></div>}
|
||||
<div className="bg-gray-600 overflow-hidden rounded-lg">
|
||||
<div className="px-4 sm:px-6 py-2 text-white">
|
||||
Your day ends at {convertMinsToHrsMins(user.endTime)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Shell>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async (context) => {
|
||||
const session = await getSession(context);
|
||||
if (!session) {
|
||||
return { redirect: { permanent: false, destination: "/auth/login" } };
|
||||
}
|
||||
|
||||
const user = await prisma.user.findFirst({
|
||||
where: {
|
||||
username: session.user.username,
|
||||
},
|
||||
select: {
|
||||
startTime: true,
|
||||
endTime: true,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
props: { user },
|
||||
};
|
||||
};
|
|
@ -13,7 +13,7 @@ function classNames(...classes) {
|
|||
export default function Home(props) {
|
||||
const [session, loading] = useSession();
|
||||
if (loading) {
|
||||
return <p className="text-gray-400">Loading...</p>;
|
||||
return <div className="loader"></div>;
|
||||
}
|
||||
|
||||
function convertMinsToHrsMins(mins) {
|
||||
|
|
|
@ -12,7 +12,7 @@ export default function integration(props) {
|
|||
const [showAPIKey, setShowAPIKey] = useState(false);
|
||||
|
||||
if (loading) {
|
||||
return <p className="text-gray-400">Loading...</p>;
|
||||
return <div className="loader"></div>;
|
||||
}
|
||||
|
||||
function toggleShowAPIKey() {
|
||||
|
|
|
@ -75,7 +75,7 @@ export default function Home({ integrations }) {
|
|||
useEffect(loadCalendars, [integrations]);
|
||||
|
||||
if (loading) {
|
||||
return <p className="text-gray-400">Loading...</p>;
|
||||
return <div className="loader"></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -8,7 +8,7 @@ export default function Billing(props) {
|
|||
const [ session, loading ] = useSession();
|
||||
|
||||
if (loading) {
|
||||
return <p className="text-gray-400">Loading...</p>;
|
||||
return <div className="loader"></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -15,7 +15,7 @@ export default function Embed(props) {
|
|||
const router = useRouter();
|
||||
|
||||
if (loading) {
|
||||
return <p className="text-gray-400">Loading...</p>;
|
||||
return <div className="loader"></div>;
|
||||
}
|
||||
|
||||
return(
|
||||
|
|
|
@ -14,7 +14,7 @@ export default function Settings(props) {
|
|||
const newPasswordRef = useRef<HTMLInputElement>();
|
||||
|
||||
if (loading) {
|
||||
return <p className="text-gray-400">Loading...</p>;
|
||||
return <div className="loader"></div>;
|
||||
}
|
||||
|
||||
const closeSuccessModal = () => { setSuccessModalOpen(false); }
|
||||
|
|
Loading…
Reference in a new issue