From 212fd1bc14a08964f72d156fec4de26af6a92633 Mon Sep 17 00:00:00 2001 From: Leo Giovanetti Date: Sat, 14 May 2022 10:49:39 -0300 Subject: [PATCH] Fixing ESLint warnings (#2723) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixing warnings * Reverting and disabling ESLint in some cases * Reverting Next Images * Reverting file, bad merge * Targeting ESLint to line * Additional warnings * New warning squished * More tweaks and major fixes * Uneeded conf Co-authored-by: Omar López --- apps/web/components/App.tsx | 7 +- apps/web/components/CustomBranding.tsx | 12 +++- apps/web/components/ImageUploader.tsx | 5 +- apps/web/components/Logo.tsx | 2 + apps/web/components/Shell.tsx | 16 +++-- apps/web/components/apps/AppCard.tsx | 5 +- apps/web/components/availability/Schedule.tsx | 2 +- .../booking/pages/AvailabilityPage.tsx | 2 +- .../components/booking/pages/BookingPage.tsx | 6 +- .../integrations/IntegrationListItem.tsx | 5 +- .../security/EnableTwoFactorModal.tsx | 5 +- .../team/TeamSettingsRightSidebar.tsx | 1 + apps/web/components/team/screens/Team.tsx | 1 + apps/web/components/ui/AuthContainer.tsx | 4 +- apps/web/components/ui/Avatar.tsx | 1 + apps/web/components/ui/AvatarSSR.tsx | 1 + apps/web/components/ui/PoweredByCal.tsx | 26 +++++--- apps/web/components/ui/WeekdaySelect.tsx | 5 +- apps/web/components/ui/form/CheckedSelect.tsx | 5 +- apps/web/ee/components/stripe/PaymentPage.tsx | 2 +- apps/web/ee/components/web3/CryptoSection.tsx | 17 +++-- apps/web/lib/hooks/useSlots.ts | 62 ++++++++++-------- apps/web/pages/404.tsx | 2 +- apps/web/pages/500.tsx | 7 +- apps/web/pages/auth/error.tsx | 2 +- apps/web/pages/auth/forgot-password/[id].tsx | 19 +++--- apps/web/pages/auth/logout.tsx | 4 +- apps/web/pages/auth/sso/[provider].tsx | 2 +- apps/web/pages/availability/troubleshoot.tsx | 2 +- apps/web/pages/event-types/[type].tsx | 1 + apps/web/pages/getting-started.tsx | 35 +++++----- apps/web/pages/success.tsx | 7 +- apps/web/pages/video/[uid].tsx | 33 ++++++---- apps/web/public/cal-logo-word-dark.svg | 9 +++ packages/app-store/googlevideo/_metadata.ts | 4 +- .../app-store/googlevideo/static/logo.webp | Bin 0 -> 4328 bytes packages/app-store/metamask/_metadata.ts | 2 +- .../app-store/wipemycalother/_metadata.ts | 4 +- packages/ui/Button.tsx | 2 +- 39 files changed, 211 insertions(+), 116 deletions(-) create mode 100644 apps/web/public/cal-logo-word-dark.svg create mode 100644 packages/app-store/googlevideo/static/logo.webp diff --git a/apps/web/components/App.tsx b/apps/web/components/App.tsx index be404f32..34d9f749 100644 --- a/apps/web/components/App.tsx +++ b/apps/web/components/App.tsx @@ -81,7 +81,7 @@ export default function App({ } } getInstalledApp(type); - }, []); + }, [type]); return ( <> @@ -94,7 +94,10 @@ export default function App({
- {name} + { + // eslint-disable-next-line @next/next/no-img-element + {name} + }

{name}

diff --git a/apps/web/components/CustomBranding.tsx b/apps/web/components/CustomBranding.tsx index 314443e3..8dd83e22 100644 --- a/apps/web/components/CustomBranding.tsx +++ b/apps/web/components/CustomBranding.tsx @@ -274,7 +274,17 @@ const BrandColor = ({ "--brand-text-color-dark-mode", getContrastingTextColor(darkVal, true) ); - }, [lightVal, darkVal]); + }, [ + embedBrandingColors.highlightColor, + embedBrandingColors.lightestColor, + embedBrandingColors.lighterColor, + embedBrandingColors.lightColor, + embedBrandingColors.medianColor, + embedBrandingColors.darkColor, + embedBrandingColors.darkerColor, + lightVal, + darkVal, + ]); return null; }; diff --git a/apps/web/components/ImageUploader.tsx b/apps/web/components/ImageUploader.tsx index 26aae806..92c87024 100644 --- a/apps/web/components/ImageUploader.tsx +++ b/apps/web/components/ImageUploader.tsx @@ -134,7 +134,10 @@ export default function ImageUploader({ {t("no_target", { target })}

)} - {imageSrc && {target}} + {imageSrc && ( + // eslint-disable-next-line @next/next/no-img-element + {target} + )}

)} {result && } diff --git a/apps/web/components/Logo.tsx b/apps/web/components/Logo.tsx index 40923b4a..08bc6632 100644 --- a/apps/web/components/Logo.tsx +++ b/apps/web/components/Logo.tsx @@ -3,8 +3,10 @@ export default function Logo({ small, icon }: { small?: boolean; icon?: boolean

{icon ? ( + // eslint-disable-next-line @next/next/no-img-element Cal ) : ( + // eslint-disable-next-line @next/next/no-img-element Cal {/* logo icon for tablet */} - + @@ -460,7 +460,6 @@ function UserDropdown({ small }: { small?: boolean }) { }, }); const utils = trpc.useContext(); - return ( @@ -470,11 +469,14 @@ function UserDropdown({ small }: { small?: boolean }) { small ? "h-8 w-8" : "h-10 w-10", "relative flex-shrink-0 rounded-full bg-gray-300 ltr:mr-3 rtl:ml-3" )}> - {user?.username + { + // eslint-disable-next-line @next/next/no-img-element + {user?.username + } {!user?.away && (
)} diff --git a/apps/web/components/apps/AppCard.tsx b/apps/web/components/apps/AppCard.tsx index 45957bb6..2512e786 100644 --- a/apps/web/components/apps/AppCard.tsx +++ b/apps/web/components/apps/AppCard.tsx @@ -20,7 +20,10 @@ export default function AppCard(props: AppCardProps) { className="block h-full rounded-sm border border-gray-300 p-5 hover:bg-neutral-50" data-testid={`app-store-app-card-${props.slug}`}>
- {props.name + { + // eslint-disable-next-line @next/next/no-img-element + {props.name + } ); @@ -103,7 +106,10 @@ const CryptoSection = (props: CryptoSectionProps) => { const connectButton = useMemo(() => { return ( ); @@ -118,7 +124,10 @@ const CryptoSection = (props: CryptoSectionProps) => { await connectMetamask(); await verifyWallet(); }}> - + { + // eslint-disable-next-line @next/next/no-img-element + MetaMask + } {t("verify_wallet")} ); diff --git a/apps/web/lib/hooks/useSlots.ts b/apps/web/lib/hooks/useSlots.ts index a54e31e5..2b1a28c2 100644 --- a/apps/web/lib/hooks/useSlots.ts +++ b/apps/web/lib/hooks/useSlots.ts @@ -122,6 +122,31 @@ export const useSlots = (props: UseSlotsProps) => { const dateTo = date.endOf("day").format(); const query = stringify({ dateFrom, dateTo, eventTypeId }); + const handleAvailableSlots = async (res: Response) => { + const responseBody: AvailabilityUserResponse = await res.json(); + const times = getSlots({ + frequency: slotInterval || eventLength, + inviteeDate: date, + workingHours: responseBody.workingHours, + minimumBookingNotice, + eventLength, + }); + const filterTimeProps = { + times, + busy: responseBody.busy, + eventLength, + beforeBufferTime, + afterBufferTime, + }; + const filteredTimes = getFilteredTimes(filterTimeProps); + // temporary + const user = res.url.substring(res.url.lastIndexOf("/") + 1, res.url.indexOf("?")); + return filteredTimes.map((time) => ({ + time, + users: [user], + })); + }; + Promise.all( users.map((user) => fetch(`/api/availability/${user.username}?${query}`).then(handleAvailableSlots)) ) @@ -173,32 +198,17 @@ export const useSlots = (props: UseSlotsProps) => { console.error(e); setError(e); }); - }, [date]); - - const handleAvailableSlots = async (res: Response) => { - const responseBody: AvailabilityUserResponse = await res.json(); - const times = getSlots({ - frequency: slotInterval || eventLength, - inviteeDate: date, - workingHours: responseBody.workingHours, - minimumBookingNotice, - eventLength, - }); - const filterTimeProps = { - times, - busy: responseBody.busy, - eventLength, - beforeBufferTime, - afterBufferTime, - }; - const filteredTimes = getFilteredTimes(filterTimeProps); - // temporary - const user = res.url.substring(res.url.lastIndexOf("/") + 1, res.url.indexOf("?")); - return filteredTimes.map((time) => ({ - time, - users: [user], - })); - }; + }, [ + afterBufferTime, + beforeBufferTime, + eventLength, + minimumBookingNotice, + slotInterval, + eventTypeId, + props.schedulingType, + users, + date, + ]); return { slots, diff --git a/apps/web/pages/404.tsx b/apps/web/pages/404.tsx index 45ca57c2..6a00ece9 100644 --- a/apps/web/pages/404.tsx +++ b/apps/web/pages/404.tsx @@ -35,7 +35,7 @@ export default function Custom404() { const [url, setUrl] = useState("https://cal.com/signup?username="); useEffect(() => { setUrl(`https://cal.com/signup?username=${username.replace("/", "")}`); - }, [router.query]); + }, [username, router.query]); const isSubpage = router.asPath.includes("/", 2); const isSignup = router.asPath.includes("/signup"); diff --git a/apps/web/pages/500.tsx b/apps/web/pages/500.tsx index 3ebc6b87..bb32c17a 100644 --- a/apps/web/pages/500.tsx +++ b/apps/web/pages/500.tsx @@ -11,7 +11,12 @@ export default function Error500() {

- 50 + 5 + { + // eslint-disable-next-line @next/next/no-img-element + 0 + } + 0

It's not you, it's us.

diff --git a/apps/web/pages/auth/error.tsx b/apps/web/pages/auth/error.tsx index c9febbca..9ad15b53 100644 --- a/apps/web/pages/auth/error.tsx +++ b/apps/web/pages/auth/error.tsx @@ -32,7 +32,7 @@ export default function Error() {

- +
diff --git a/apps/web/pages/auth/forgot-password/[id].tsx b/apps/web/pages/auth/forgot-password/[id].tsx index b7bae37b..6bbdf86a 100644 --- a/apps/web/pages/auth/forgot-password/[id].tsx +++ b/apps/web/pages/auth/forgot-password/[id].tsx @@ -63,13 +63,16 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {

{t("password_has_been_reset_login")}

- - - + { + // eslint-disable-next-line @next/next/link-passhref + + + + } ); @@ -84,7 +87,7 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {

{t("request_is_expired")}

{t("request_is_expired_instructions")}

- + diff --git a/apps/web/pages/auth/sso/[provider].tsx b/apps/web/pages/auth/sso/[provider].tsx index 8627edd9..1c8e914d 100644 --- a/apps/web/pages/auth/sso/[provider].tsx +++ b/apps/web/pages/auth/sso/[provider].tsx @@ -38,7 +38,7 @@ export default function Provider(props: SSOProviderPageProps) { } else { signIn(props.provider); } - }, []); + }, [props.isSAMLLoginEnabled, props.product, props.provider, props.tenant, router]); return null; } diff --git a/apps/web/pages/availability/troubleshoot.tsx b/apps/web/pages/availability/troubleshoot.tsx index 2b223073..9d6330cc 100644 --- a/apps/web/pages/availability/troubleshoot.tsx +++ b/apps/web/pages/availability/troubleshoot.tsx @@ -48,7 +48,7 @@ const AvailabilityView = ({ user }: { user: User }) => { }); }; fetchAvailability(selectedDate); - }, [selectedDate]); + }, [user.username, selectedDate]); return (
diff --git a/apps/web/pages/event-types/[type].tsx b/apps/web/pages/event-types/[type].tsx index 87e55076..a88cb3c5 100644 --- a/apps/web/pages/event-types/[type].tsx +++ b/apps/web/pages/event-types/[type].tsx @@ -329,6 +329,7 @@ const EventTypePage = (props: inferSSRProps) => { fetchTokens(); !hashedUrl && setHashedUrl(generateHashedLink(eventType.users[0].id)); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); async function deleteEventTypeHandler(event: React.MouseEvent) { diff --git a/apps/web/pages/getting-started.tsx b/apps/web/pages/getting-started.tsx index e14d6bf7..b8313674 100644 --- a/apps/web/pages/getting-started.tsx +++ b/apps/web/pages/getting-started.tsx @@ -12,7 +12,7 @@ import { NextPageContext } from "next"; import { useSession } from "next-auth/react"; import Head from "next/head"; import { useRouter } from "next/router"; -import React, { useEffect, useRef, useState } from "react"; +import React, { useEffect, useRef, useState, useCallback } from "react"; import { useForm } from "react-hook-form"; import TimezoneSelect from "react-timezone-select"; import * as z from "zod"; @@ -102,21 +102,24 @@ export default function Onboarding(props: inferSSRProps(null); - const updateUser = async (data: Prisma.UserUpdateInput) => { - const res = await fetch(`/api/user/${props.user.id}`, { - method: "PATCH", - body: JSON.stringify({ data: { ...data } }), - headers: { - "Content-Type": "application/json", - }, - }); + const updateUser = useCallback( + async (data: Prisma.UserUpdateInput) => { + const res = await fetch(`/api/user/${props.user.id}`, { + method: "PATCH", + body: JSON.stringify({ data: { ...data } }), + headers: { + "Content-Type": "application/json", + }, + }); - if (!res.ok) { - throw new Error((await res.json()).message); - } - const responseData = await res.json(); - return responseData.data; - }; + if (!res.ok) { + throw new Error((await res.json()).message); + } + const responseData = await res.json(); + return responseData.data; + }, + [props.user.id] + ); const createEventType = async (data: Prisma.EventTypeCreateInput) => { const res = await fetch(`/api/availability/eventtype`, { @@ -288,7 +291,7 @@ export default function Onboarding(props: inferSSRProps - {giphyImage && !needsConfirmation && {"Gif} + {giphyImage && !needsConfirmation && ( + // eslint-disable-next-line @next/next/no-img-element + {"Gif + )} {!giphyImage && !needsConfirmation && ( )} diff --git a/apps/web/pages/video/[uid].tsx b/apps/web/pages/video/[uid].tsx index 488dc0d4..5353ae9b 100644 --- a/apps/web/pages/video/[uid].tsx +++ b/apps/web/pages/video/[uid].tsx @@ -96,8 +96,14 @@ export default function JoinCall(props: JoinCallPageProps) { token: props.booking.dailyRef?.dailytoken, }); } - }, []); - + }, [ + emptyBooking, + meetingUnavailable, + props.booking?.dailyRef?.dailytoken, + props.booking?.dailyRef?.dailyurl, + props.booking?.user?.id, + session?.userid, + ]); return ( <> @@ -116,16 +122,19 @@ export default function JoinCall(props: JoinCallPageProps) {
- - Cal.com Logo + + { + // eslint-disable-next-line @next/next/no-img-element + Cal.com Logo + } {JoinCall}
diff --git a/apps/web/public/cal-logo-word-dark.svg b/apps/web/public/cal-logo-word-dark.svg new file mode 100644 index 00000000..e12d2875 --- /dev/null +++ b/apps/web/public/cal-logo-word-dark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/app-store/googlevideo/_metadata.ts b/packages/app-store/googlevideo/_metadata.ts index 32889bc4..aa1e85ee 100644 --- a/packages/app-store/googlevideo/_metadata.ts +++ b/packages/app-store/googlevideo/_metadata.ts @@ -12,9 +12,9 @@ export const metadata = { category: "video", type: "google_video", title: "Google Meet", - imageSrc: "https://cdn.iconscout.com/icon/free/png-256/google-meet-2923654-2416657.png", + imageSrc: "/api/app-store/googlevideo/logo.webp", variant: "conferencing", - logo: "https://cdn.iconscout.com/icon/free/png-256/google-meet-2923654-2416657.png", + logo: "/api/app-store/googlevideo/logo.webp", publisher: "Cal.com", rating: 5, reviews: 69, diff --git a/packages/app-store/googlevideo/static/logo.webp b/packages/app-store/googlevideo/static/logo.webp new file mode 100644 index 0000000000000000000000000000000000000000..5443580ff53f3fa018368dc9a85f40ee0d3ee978 GIT binary patch literal 4328 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 )}