Closed nzayatz14 closed 1 month ago
Was not able to replicate the issue. 🤔
@Souptik2001 yea its not super easy to replicate it. It took me about 6 hours of working on the page after I was first shown the issue to see it on my machine.
After digging through the code a bit, I think it may have something to do with this block in embed.ts
let currentColorScheme: string | null = null;
(function watchAndActOnColorSchemeChange() {
// TODO: Maybe find a better way to identify change in color-scheme, a mutation observer seems overkill for this. Settle with setInterval for now.
setInterval(() => {
const colorScheme = getColorScheme(document.body);
if (colorScheme && colorScheme !== currentColorScheme) {
currentColorScheme = colorScheme;
// Go through all the embeds on the same page and update all of them with this info
CalApi.initializedNamespaces.forEach((ns) => {
const api = getEmbedApiFn(ns);
api("ui", {
colorScheme: colorScheme,
});
});
}
}, 50);
})();
Maybe somehow this function gets called twice, and 2 intervals get set because neither get cancelled and it just bops back and forth? Once it happens again ill try to set a breakpoint and see if thats the case.
thats the disco mode
just kidding
lemme try to find someone to fix this
Hi both,
I'm using NextJS and the React version of the inline embed and having the same issue in both dev and prod environments but only when opening up 2 or more instances of the same page on the same device. Doesn't seem to cause an issue in production testing the same page route of separate devices.
Here's a loom of the behaviour I'm getting: https://www.loom.com/share/283f6cd08e8941f18e4e1d9a95cd9480?sid=64f89ba4-06c4-4583-af2e-697072127c17
@nzayatz14 does this only occur when you have two instances of the page open during development?
Here's my code for the calendar component:
'use client';
import { useEffect } from 'react';
import Cal, { getCalApi } from '@calcom/embed-react';
export default function BookingCalendar() {
const calURL = 'example/call';
useEffect(() => {
(async function () {
const cal = await getCalApi();
cal('ui', {
theme: 'dark',
styles: { branding: { brandColor: '#24332B' } },
hideEventTypeDetails: false,
layout: 'month_view',
});
})();
}, []);
return (
<Cal
calLink={calURL}
style={{
width: '100%',
height: '100%',
overflow: 'scroll',
}}
config={{ layout: 'month_view' }}
/>
)
}
Hi,
I have the same issue, also using NextJS and the react embed code given by the application, using the pop-up method. Here is how you can reproduce the issue:
$ npx create-next-app@latest calcom-flicker-issue # Keep the default settings
✔ Would you like to use TypeScript? … No / **Yes**
✔ Would you like to use ESLint? … No / **Yes**
✔ Would you like to use Tailwind CSS? … No / **Yes**
✔ Would you like to use `src/` directory? … **No** / Yes
✔ Would you like to use App Router? (recommended) … No / **Yes**
✔ Would you like to customize the default import alias (@/*)? … **No** / Yes
...
$ cd calcom-flicker-issue
$ npm install @calcom/embed-react
Replace the content of app/page.tsx
with:
import { Suspense } from "react";
import { CalComButton } from "./calcomButton";
export default function Home() {
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<Suspense>
<CalComButton />
</Suspense>
</main>
);
}
Create the file app/CalComButton.tsx
with:
"use client";
import { getCalApi } from "@calcom/embed-react";
import { useEffect } from "react";
export function CalComButton() {
useEffect(() => {
(async function () {
const cal = await getCalApi();
cal("ui", {
theme: "light",
styles: { branding: { brandColor: "#00ff00" } },
});
})();
}, []);
return <button data-cal-link="rick">Click me</button>;
}
Now you can run your local server with:
$ npm run dev
Navigating to localhost:3000 should show a single button on a black background.
At this point, the remaining steps are:
My default desktop theme is dark, so I pick the "light" theme in the file app/CalComButton.tsx
. You might have to do the reverse to see the flicker. It takes 2 pop-ups for the flicker to show up, as explained in other comments.
Happy to provide more information if needed to help with reproducing the issue.
For anyone facing this issue, could you try the following:
Set config.theme
same as the theme you set through ui instruction.
So the code becomes something like this. Notice config param in Cal component being passed has theme now
'use client';
import { useEffect } from 'react';
import Cal, { getCalApi } from '@calcom/embed-react';
export default function BookingCalendar() {
const calURL = 'example/call';
useEffect(() => {
(async function () {
const cal = await getCalApi();
cal('ui', {
theme: 'dark',
styles: { branding: { brandColor: '#24332B' } },
hideEventTypeDetails: false,
layout: 'month_view',
});
})();
}, []);
return (
<Cal
calLink={calURL}
style={{
width: '100%',
height: '100%',
overflow: 'scroll',
}}
config={{ layout: 'month_view' , theme:'dark'}}
/>
)
}
When set through config
, theme is passed via query param which makes it always available. Setting it via 'ui' instruction has somehow started getting delayed by the browser(so it seems) causing us to wrongly calculate the storageKey for next-theme
Hey @hariombalhara, my original post has that theme explicitly set
@nzayatz14 I see it set only in "ui" instruction I am talking about setting in config. For Vanilla JS/HTML popup it requires setting a data attribute on the element that triggers the popup.
data-cal-config='{"theme":"dark"}'
@hariombalhara ah ok, is there a version of this for the VanillaJS HTML standard embedding (no popup)?
<script type="text/javascript">
(function (C, A, L) {
let p = function (a, ar) {
a.q.push(ar);
};
let d = C.document;
C.Cal =
C.Cal ||
function () {
let cal = C.Cal;
let ar = arguments;
if (!cal.loaded) {
cal.ns = {};
cal.q = cal.q || [];
d.head.appendChild(d.createElement('script')).src = A;
cal.loaded = true;
}
if (ar[0] === L) {
const api = function () {
p(api, arguments);
};
const namespace = ar[1];
api.q = api.q || [];
if (typeof namespace === 'string') {
cal.ns[namespace] = cal.ns[namespace] || api;
p(cal.ns[namespace], ar);
p(cal, ['initNamespace', namespace]);
} else p(cal, ar);
return;
}
p(cal, ar);
};
})(window, 'https://app.cal.com/embed/embed.js', 'init');
Cal('init', '30min', { origin: 'https://cal.com' });
Cal.ns['30min']('inline', {
elementOrSelector: '#my-cal-inline',
calLink: '...',
layout: 'month_view',
});
Cal.ns['30min']('ui', {
theme: 'dark',
styles: { branding: { brandColor: '#3aaf4b' } },
hideEventTypeDetails: false,
layout: 'month_view',
});
</script>
Yeah, you pass config like this
Cal.ns['30min']('inline', {
elementOrSelector: '#my-cal-inline',
calLink: '...',
config: {
// Setting theme through config is synchronous because it is passed as query param. So, do it here as well for best experience. After setting this it is optional to set the theme using "ui" instruction
theme: "dark"
}
.....
Let me know if it fixes the issue for you.
I'll add it and keep an eye out, thanks! You may want to add that to the code you generate when clicking on the embed options from inside the cal.com web app. Right now it only uses the ui instruction.
Could the issue be that it is flopping back and forth between the value in the config (which may or may not be set) and the one set in the ui instruction?
Yeah, I am working on it https://github.com/calcom/cal.com/pull/16042
Actually it wasn't really needed earlier and to keep the code concise, I didn't add it. But due to some timing issue that recently started happening, it has become a requirement now(it seems). I spent quite some time figuring out, what changed due to which the issue started coming and nothing has changed in the flow.
Somehow, either the UI postmessage is taking longer to execute actually or cal.com AppProvider is getting initialized much faster. These are the only 2 reasons the issue can come.
But anyway it is better to guarantee that theme is available when AppProvider initializes, so I am going to update the config anyway for all codes.
@hariombalhara I can confirm that for the embed, the change that you propsed earlier:
data-cal-config='{"theme":"dark"}'
Indeed fixes the issue. For reference, this is what the content of the file calcomButton.tsx
becomes after the change:
"use client";
import { getCalApi } from "@calcom/embed-react";
import { useEffect } from "react";
export function CalComButton() {
useEffect(() => {
(async function () {
const cal = await getCalApi();
cal("ui", {
theme: "light",
styles: { branding: { brandColor: "#00ff00" } },
});
})();
}, []);
return (
<button data-cal-link="rick" data-cal-config='{"theme": "light"}'>
Click me
</button>
);
}
Hey @hariombalhara I just set the config.theme
to be the same as the theme you set through ui instruction as you suggested.
Has fixed the issue for me, thanks!!
Issue Summary
Hi there! I have an embedded cal.com link in my website for people to schedule calls with. My website has a dark theme so I set the javascript to initialize the theme in dark mode:
Occasionally when I load the page, the calendar will flicker between light and dark themes infinitely. It looks like the
class
value in the<html>
tag keeps switching betweenclass="light"
andclass="dark"
. Here is a video:https://github.com/user-attachments/assets/64f4d89b-26e1-4990-972f-c873dc7ebaaa
I did a bit of testing and it appears to be looping between the theme that the javascript value has passed in (
dark
) and the theme of the browser (my browser islight
theme). Even if they are both the same value (in my casedark
anddark
), my browser shows the value continuously being re-rendered. Watch the video below that shows the<html>
objects class being continuously updated.https://github.com/user-attachments/assets/65d0cafc-eeac-4cf8-b2c7-22d8a6f26041
Steps to Reproduce
Embed a cal.com month view in your website using the instructions in the web app and refresh the page enough times.
Expected behavior
The calendar should not flicker.
Other information
No response
Screenshots
No response
Environment
Desktop (please complete the following information)
From SyncLinear.com | CAL-4095