Skip to content

Commit 7d44454

Browse files
authored
improvements: mask as read when opening notifications, show custom domain, and more (#1042)
* mark as read when opening notifications, ref red alert when clicked is hidden, etc.. * Update Items.tsx
1 parent f46a1d3 commit 7d44454

File tree

7 files changed

+117
-30
lines changed

7 files changed

+117
-30
lines changed

apps/web/app/(org)/dashboard/Contexts.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ type SharedContext = {
2323
sidebarCollapsed: boolean;
2424
upgradeModalOpen: boolean;
2525
setUpgradeModalOpen: (open: boolean) => void;
26+
referClickedState: boolean;
27+
setReferClickedStateHandler: (referClicked: boolean) => void;
2628
};
2729

2830
type ITheme = "light" | "dark";
@@ -52,6 +54,7 @@ export function DashboardContexts({
5254
anyNewNotifications,
5355
initialTheme,
5456
initialSidebarCollapsed,
57+
referClicked,
5558
}: {
5659
children: React.ReactNode;
5760
organizationData: SharedContext["organizationData"];
@@ -63,12 +66,14 @@ export function DashboardContexts({
6366
anyNewNotifications: boolean;
6467
initialTheme: ITheme;
6568
initialSidebarCollapsed: boolean;
69+
referClicked: boolean;
6670
}) {
6771
const [theme, setTheme] = useState<ITheme>(initialTheme);
6872
const [sidebarCollapsed, setSidebarCollapsed] = useState(
6973
initialSidebarCollapsed,
7074
);
7175
const [upgradeModalOpen, setUpgradeModalOpen] = useState(false);
76+
const [referClickedState, setReferClickedState] = useState(referClicked);
7277
const pathname = usePathname();
7378

7479
// Calculate user's spaces (both owned and member of)
@@ -125,13 +130,21 @@ export function DashboardContexts({
125130
document.body.className = "light";
126131
};
127132
}, [theme]);
133+
128134
const toggleSidebarCollapsed = () => {
129135
setSidebarCollapsed(!sidebarCollapsed);
130136
Cookies.set("sidebarCollapsed", !sidebarCollapsed ? "true" : "false", {
131137
expires: 365,
132138
});
133139
};
134140

141+
const setReferClickedStateHandler = (referClicked: boolean) => {
142+
setReferClickedState(referClicked);
143+
Cookies.set("referClicked", referClicked ? "true" : "false", {
144+
expires: 365,
145+
});
146+
};
147+
135148
return (
136149
<ThemeContext.Provider value={{ theme, setThemeHandler }}>
137150
<DashboardContext.Provider
@@ -150,6 +163,8 @@ export function DashboardContexts({
150163
sidebarCollapsed,
151164
upgradeModalOpen,
152165
setUpgradeModalOpen,
166+
referClickedState,
167+
setReferClickedStateHandler,
153168
}}
154169
>
155170
{children}

apps/web/app/(org)/dashboard/_components/Navbar/CapAIBox.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ const CapAIBox = ({
2424
}}
2525
onMouseEnter={() => setHovered(true)}
2626
onMouseLeave={() => setHovered(false)}
27-
className="hidden p-3 mb-6 w-full rounded-xl border transition-colors cursor-pointer md:block hover:bg-gray-2 h-fit border-gray-3"
27+
className="hidden p-3 mb-6 w-[calc(100%-12px)] mx-auto rounded-xl border transition-colors cursor-pointer md:block hover:bg-gray-2 h-fit border-gray-3"
2828
>
2929
<div className="flex justify-between items-center px-3 pb-3 w-full">
3030
<h3 className="text-sm font-medium text-gray-12">Cap AI</h3>
31-
<p className="text-xs text-gray-10">Available now</p>
31+
<p className="text-[11px] text-gray-10">Available now</p>
3232
</div>
3333
<CapAIArt />
3434
<div

apps/web/app/(org)/dashboard/_components/Navbar/CapAIDialog.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const CapAIDialog = ({ setOpen }: { setOpen: (open: boolean) => void }) => {
5050
<h4 className="text-sm font-medium text-gray-12">
5151
Features include:
5252
</h4>
53-
<ul className="flex flex-wrap gap-2 text-sm text-gray-11">
53+
<ul className="flex flex-wrap gap-2 text-sm text-gray-12">
5454
{[
5555
"Auto-generated titles",
5656
"Recording summaries",
@@ -65,7 +65,7 @@ const CapAIDialog = ({ setOpen }: { setOpen: (open: boolean) => void }) => {
6565
icon={faWandMagicSparkles}
6666
className="mr-2 mt-0.5 text-blue-11 size-3"
6767
/>
68-
<span>{feature}</span>
68+
<span className="text-gray-12">{feature}</span>
6969
</li>
7070
))}
7171
</ul>

apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ import {
1919
PopoverTrigger,
2020
} from "@cap/ui";
2121
import { classNames } from "@cap/utils";
22-
import { faBuilding } from "@fortawesome/free-solid-svg-icons";
22+
import {
23+
faBuilding,
24+
faCircleInfo,
25+
faLink,
26+
} from "@fortawesome/free-solid-svg-icons";
2327
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
2428
import clsx from "clsx";
2529
import { AnimatePresence, motion } from "framer-motion";
@@ -104,13 +108,13 @@ const AdminNavItems = ({ toggleMobileNav }: Props) => {
104108
duration: 0.2,
105109
}}
106110
className={clsx(
107-
"mt-1.5 mx-auto p-2.5 rounded-xl cursor-pointer bg-gray-3",
108-
sidebarCollapsed ? "w-fit" : "w-full",
111+
"mt-1.5 mx-auto rounded-xl cursor-pointer bg-gray-3",
112+
sidebarCollapsed ? "w-fit px-2 py-0.5" : "w-full p-2.5",
109113
)}
110114
>
111115
<div
112116
className={clsx(
113-
"flex items-center cursor-pointer",
117+
"flex flex-col items-center cursor-pointer",
114118
sidebarCollapsed ? "justify-center" : "justify-between",
115119
)}
116120
role="combobox"
@@ -121,7 +125,7 @@ const AdminNavItems = ({ toggleMobileNav }: Props) => {
121125
"flex items-center",
122126
sidebarCollapsed
123127
? "justify-center w-fit"
124-
: "justify-between w-full",
128+
: "justify-between gap-2.5 w-full",
125129
)}
126130
>
127131
<div className="flex items-center">
@@ -139,31 +143,69 @@ const AdminNavItems = ({ toggleMobileNav }: Props) => {
139143
) : (
140144
<Avatar
141145
letterClass={clsx(
142-
sidebarCollapsed ? "text-sm" : "text-[11px]",
146+
sidebarCollapsed ? "text-sm" : "text-[13px]",
143147
)}
144148
className={clsx(
145149
"relative flex-shrink-0 mx-auto",
146-
sidebarCollapsed ? "size-6" : "size-5",
150+
sidebarCollapsed ? "size-6" : "size-7",
147151
)}
148152
name={
149153
activeOrg?.organization.name ??
150154
"No organization found"
151155
}
152156
/>
153157
)}
158+
</div>
159+
<div className="flex flex-col flex-1 items-center h-10">
160+
<div className="flex justify-between items-center w-full">
161+
{!sidebarCollapsed && (
162+
<p className="text-sm truncate leading-0 text-gray-12">
163+
{activeOrg?.organization.name ??
164+
"No organization found"}
165+
</p>
166+
)}
167+
{!sidebarCollapsed && (
168+
<ChevronDown
169+
data-state={open ? "open" : "closed"}
170+
className="size-4 transition-transform duration-200 text-gray-10 data-[state=open]:rotate-180"
171+
/>
172+
)}
173+
</div>
154174
{!sidebarCollapsed && (
155-
<p className="ml-2.5 text-sm text-gray-12 truncate">
156-
{activeOrg?.organization.name ??
157-
"No organization found"}
158-
</p>
175+
<Link
176+
href={
177+
activeOrg?.organization.customDomain
178+
? `https://${activeOrg.organization.customDomain}`
179+
: "/dashboard/settings/organization"
180+
}
181+
rel={
182+
activeOrg?.organization.customDomain
183+
? "noopener noreferrer"
184+
: undefined
185+
}
186+
target={
187+
activeOrg?.organization.customDomain
188+
? "_blank"
189+
: "_self"
190+
}
191+
className="flex truncate w-full overflow-hidden flex-1 gap-1.5 items-center self-start"
192+
>
193+
<FontAwesomeIcon
194+
icon={
195+
activeOrg?.organization.customDomain
196+
? faLink
197+
: faCircleInfo
198+
}
199+
className="duration-200 size-3 text-gray-10"
200+
/>
201+
<p className="w-full text-[11px] flex-1 duration-200 truncate leading-0 text-gray-11">
202+
{activeOrg?.organization.customDomain
203+
? activeOrg?.organization.customDomain
204+
: "No custom domain set"}
205+
</p>
206+
</Link>
159207
)}
160208
</div>
161-
{!sidebarCollapsed && (
162-
<ChevronDown
163-
data-state={open ? "open" : "closed"}
164-
className="w-5 h-auto transition-transform duration-200 text-gray-8 data-[state=open]:rotate-180"
165-
/>
166-
)}
167209
</div>
168210
</div>
169211
<PopoverContent

apps/web/app/(org)/dashboard/_components/Navbar/Top.tsx

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
} from "@cap/ui";
1313
import { faBell, faMoon, faSun } from "@fortawesome/free-solid-svg-icons";
1414
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
15+
import { useMutation, useQueryClient } from "@tanstack/react-query";
1516
import { useClickAway } from "@uidotdev/usehooks";
1617
import clsx from "clsx";
1718
import { AnimatePresence } from "framer-motion";
@@ -28,6 +29,7 @@ import {
2829
useRef,
2930
useState,
3031
} from "react";
32+
import { markAsRead } from "@/actions/notifications/mark-as-read";
3133
import Notifications from "@/app/(org)/dashboard/_components/Notifications";
3234
import { UpgradeModal } from "@/components/UpgradeModal";
3335
import { useDashboardContext, useTheme } from "../../Contexts";
@@ -44,10 +46,12 @@ import type { DownloadIconHandle } from "../AnimatedIcons/Download";
4446
import type { ReferIconHandle } from "../AnimatedIcons/Refer";
4547

4648
const Top = () => {
47-
const { activeSpace, anyNewNotifications } = useDashboardContext();
49+
const { activeSpace, anyNewNotifications, activeOrganization } =
50+
useDashboardContext();
4851
const [toggleNotifications, setToggleNotifications] = useState(false);
4952
const bellRef = useRef<HTMLDivElement>(null);
5053
const { theme, setThemeHandler } = useTheme();
54+
const queryClient = useQueryClient();
5155

5256
const pathname = usePathname();
5357

@@ -75,6 +79,18 @@ const Top = () => {
7579
},
7680
);
7781

82+
const markAllAsread = useMutation({
83+
mutationFn: () => markAsRead(),
84+
onSuccess: () => {
85+
queryClient.invalidateQueries({
86+
queryKey: ["notifications"],
87+
});
88+
},
89+
onError: (error) => {
90+
console.error("Error marking notifications as read:", error);
91+
},
92+
});
93+
7894
return (
7995
<div
8096
className={clsx(
@@ -112,11 +128,17 @@ const Top = () => {
112128
data-state={toggleNotifications ? "open" : "closed"}
113129
ref={bellRef}
114130
onClick={() => {
131+
if (anyNewNotifications) {
132+
markAllAsread.mutate();
133+
}
115134
setToggleNotifications(!toggleNotifications);
116135
}}
117136
onKeyDown={(e) => {
118137
if (e.key === "Enter" || e.key === " ") {
119138
e.preventDefault();
139+
if (anyNewNotifications) {
140+
markAllAsread.mutate();
141+
}
120142
setToggleNotifications(!toggleNotifications);
121143
}
122144
}}
@@ -337,18 +359,24 @@ const MenuItem = memo(({ icon, name, href, onClick, iconClassName }: Props) => {
337359

338360
const ReferButton = () => {
339361
const iconRef = useRef<ReferIconHandle>(null);
362+
const { setReferClickedStateHandler, referClickedState } =
363+
useDashboardContext();
340364

341365
return (
342366
<Link href="/dashboard/refer" className="hidden relative lg:block">
343-
{/* Red notification dot with pulse animation */}
344-
<div className="absolute right-0 top-1 z-10">
345-
<div className="relative">
346-
<div className="absolute inset-0 w-2 h-2 bg-red-400 rounded-full opacity-75 animate-ping" />
347-
<div className="relative w-2 h-2 bg-red-400 rounded-full" />
367+
{!referClickedState && (
368+
<div className="absolute right-0 top-1 z-10">
369+
<div className="relative">
370+
<div className="absolute inset-0 w-2 h-2 bg-red-400 rounded-full opacity-75 animate-ping" />
371+
<div className="relative w-2 h-2 bg-red-400 rounded-full" />
372+
</div>
348373
</div>
349-
</div>
374+
)}
350375

351376
<div
377+
onClick={() => {
378+
setReferClickedStateHandler(true);
379+
}}
352380
onMouseEnter={() => {
353381
iconRef.current?.startAnimation();
354382
}}

apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ export const CapCard = ({
404404
{!sharedCapCard && onSelectToggle && (
405405
<div
406406
className={clsx(
407-
"absolute top-2 left-2 z-[20] duration-200",
407+
"absolute top-2 left-2 z-[51] duration-200",
408408
isSelected || anyCapSelected || isDropdownOpen
409409
? "opacity-100"
410410
: "group-hover:opacity-100 opacity-0",
@@ -467,7 +467,7 @@ export const CapCard = ({
467467
className="text-white size-3"
468468
/>
469469
</div>
470-
<p className="text-xs text-center text-white">
470+
<p className="text-[13px] text-center text-white">
471471
Upload failed
472472
</p>
473473
</div>

apps/web/app/(org)/dashboard/layout.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export default async function DashboardLayout({
6565

6666
const theme = cookies().get("theme")?.value ?? "light";
6767
const sidebar = cookies().get("sidebarCollapsed")?.value ?? "false";
68+
const referClicked = cookies().get("referClicked")?.value ?? "false";
6869

6970
return (
7071
<UploadingProvider>
@@ -78,6 +79,7 @@ export default async function DashboardLayout({
7879
initialSidebarCollapsed={sidebar === "true"}
7980
anyNewNotifications={anyNewNotifications}
8081
userPreferences={userPreferences}
82+
referClicked={referClicked === "true"}
8183
>
8284
<div className="dashboard-grid">
8385
<DesktopNav />

0 commit comments

Comments
 (0)