Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions apps/web/src/app/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Settings } from "@/components/settings";
import { Suspense } from "react";

export default function SettingsPage() {
// let's keep this page here for SSR, possibly to prefech some data on the server side, suspense queries etc.

return (
<>
<Suspense fallback="">
<Settings />
</>
</Suspense>
);
}
4 changes: 2 additions & 2 deletions apps/web/src/components/CompaniesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import CompaniesListFooter from "./CompaniesListFooter";
import { CompaniesListHeader } from "./CompaniesListHeader";
import CompanyItem from "./CompanyItem";
import { EmptyState } from "./EmptyState";
import SponsorSideSection from "./SponsorSideSection";
import { NotificationsSideSection } from "./NotificationsSideSection";

const PAGE_SIZE = 15;

Expand Down Expand Up @@ -89,7 +89,7 @@ export default function CompaniesList({
</div>
)}
<div className="block lg:hidden space-y-4">
<SponsorSideSection />
<NotificationsSideSection />
</div>
</>
);
Expand Down
27 changes: 27 additions & 0 deletions apps/web/src/components/NotificationsSideSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { SettingsTab } from "@/lib/search-params";
import Link from "next/link";
import { Button } from "./ui/button";
import { RetroContainer } from "./ui/retro-container";

export const NotificationsSideSection = () => {
return (
<RetroContainer
variant="static-secondary"
className="px-4 py-3 lg:w-[290px]"
>
<div className="flex flex-wrap items-center justify-center w-full gap-2">
<div className="flex-1 min-w-[180px]">
<h2 className="text-lg font-semibold">Stay updated 🔔</h2>
<p className="text-xs text-muted-foreground">
Get notified when new companies are added.
</p>
</div>
<Button variant="default" size="sm" className="px-2" asChild>
<Link href={`/settings?tab=${SettingsTab.NOTIFICATIONS}`} prefetch>
Subscribe now
</Link>
</Button>
</div>
</RetroContainer>
);
};
5 changes: 2 additions & 3 deletions apps/web/src/components/SideBar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { NotificationsSideSection } from "./NotificationsSideSection";
import { SearchSideBar } from "./SearchSideBar";
import SponsorSideSection from "./SponsorSideSection";

type SideBarProps = {
locationOptions: string[];
Expand All @@ -9,8 +9,7 @@ type SideBarProps = {
export function SideBar({ locationOptions, categoryOptions }: SideBarProps) {
return (
<aside className="h-fit shrink-0 flex-col gap-4 lg:sticky lg:top-[60px] lg:flex-col-reverse hidden lg:flex">
{/* <FeaturedSideSection /> */}
<SponsorSideSection />
<NotificationsSideSection />
<SearchSideBar {...{ locationOptions, categoryOptions }} />
</aside>
);
Expand Down
27 changes: 0 additions & 27 deletions apps/web/src/components/SponsorSideSection.tsx

This file was deleted.

30 changes: 17 additions & 13 deletions apps/web/src/components/settings/index.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,41 @@
"use client";

import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import type { SettingsTab } from "@/lib/types";
import { SettingsTab, settingsQueryStateKeys } from "@/lib/search-params";
import type { SettingsTabs } from "@/lib/types";
import { cn } from "@/lib/utils";
import { trackEvent } from "@tech-companies-portugal/analytics/client";
import { useQueryStates } from "nuqs";
import { Title } from "../Title";
import { AccountSettings } from "./account/AccountSettings";
import { NotificationSettings } from "./notification/NotificationSettings";

const TABS: SettingsTab[] = [
const TABS: SettingsTabs[] = [
{
id: "account",
id: SettingsTab.ACCOUNT,
title: "Account",
},
{
id: "notifications",
id: SettingsTab.NOTIFICATIONS,
title: "Notifications",
},
];

export const Settings = () => {
const [settingsTab, setSettingsTab] = useQueryStates(settingsQueryStateKeys, {
scroll: true,
});

return (
<div className="container mx-auto max-w-2xl p-6">
<div className="mb-6">
<Title title="Settings" description="Manage your account settings." />
</div>

<Tabs defaultValue="account" className="bold">
<Tabs
value={settingsTab.tab}
onValueChange={(value) => setSettingsTab({ tab: value as SettingsTab })}
className="bold"
>
<TabsList className="bg-transparent flex justify-start gap-4 w-full mb-4 overflow-x-auto scrollbar-hide">
{TABS.map((tab) => (
<TabsTrigger
Expand All @@ -38,18 +47,13 @@ export const Settings = () => {
)}
>
{tab.title}
{tab.badge && tab.badge}
</TabsTrigger>
))}
</TabsList>
<TabsContent value="account" className="p-0.5">
<TabsContent value={SettingsTab.ACCOUNT} className="p-0.5">
<AccountSettings />
</TabsContent>
<TabsContent
value="notifications"
className="p-0.5"
onClick={() => trackEvent("notifications_tab_clicked")}
>
<TabsContent value={SettingsTab.NOTIFICATIONS} className="p-0.5">
<NotificationSettings />
</TabsContent>
</Tabs>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { memo, useCallback } from "react";
import { useThrottledCallback } from "use-debounce";

const NOTIFICATION_LABEL_MAP = {
new_companies: "Receive weekly email updates for new companies added",
new_companies: "Receive email updates for new companies added",
} as const;

export const NotificationSettings = () => {
Expand Down
23 changes: 23 additions & 0 deletions apps/web/src/lib/search-params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
createSearchParamsCache,
parseAsFloat,
parseAsString,
parseAsStringEnum,
} from "nuqs/server";

export const defaultSearchParams = {
Expand All @@ -12,6 +13,15 @@ export const defaultSearchParams = {
page: 1,
};

export enum SettingsTab {
ACCOUNT = "account",
NOTIFICATIONS = "notifications",
}

export const defaultSettings = {
tab: SettingsTab.ACCOUNT,
};

// can be used in the client as well
export const searchParamsQueryStateKeys = {
query: parseAsString.withDefault(defaultSearchParams.query),
Expand All @@ -27,3 +37,16 @@ export const loadSearchParams = createLoader(searchParamsQueryStateKeys);
export const searchParamsCache = createSearchParamsCache(
searchParamsQueryStateKeys,
);

// query state keys for the settings page
export const settingsQueryStateKeys = {
tab: parseAsStringEnum<SettingsTab>(Object.values(SettingsTab)).withDefault(
defaultSettings.tab,
),
};

// for server side
export const loadSettings = createLoader(settingsQueryStateKeys);

// For getting server side cached settings in nested components tree
export const settingsCache = createSearchParamsCache(settingsQueryStateKeys);
6 changes: 4 additions & 2 deletions apps/web/src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { SettingsTab } from "./search-params";

export type Company = {
slug: string;
name: string;
Expand Down Expand Up @@ -27,8 +29,8 @@ export type PageViewsData = {

export type NextParams<T> = Promise<T>;

export type SettingsTab = {
id: string;
export type SettingsTabs = {
id: SettingsTab;
title: string;
disabled?: boolean;
badge?: React.ReactNode;
Expand Down