Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/notification system #783

Closed
wants to merge 13 commits into from
Closed
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-select": "^2.1.1",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-switch": "^1.1.0",
"@radix-ui/react-tabs": "^1.1.0",
Expand Down
33 changes: 23 additions & 10 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
"use client";

import { BellRing } from "lucide-react";
import { FC } from "react";

import { useNotificationStore } from "~/app/dashboard/(user-dashboard)/settings/notification/action/notification-store";
import { notificationSettingsProperties } from "~/app/dashboard/(user-dashboard)/settings/notification/types/notification-settings.types";
import CustomButton from "~/components/common/common-button/common-button";
import {
Card,
Expand Down Expand Up @@ -29,6 +33,12 @@ const UnreadNotificationCard: FC<CardProperties> = ({
unreadCount = 0,
...properties
}) => {
const { settings, updateSettings } = useNotificationStore();

const handleToggleSwitch = (name: keyof notificationSettingsProperties) => {
updateSettings({ [name]: !settings[name] });
};

return (
<Card
data-testid="cardContainer"
Expand All @@ -44,7 +54,7 @@ const UnreadNotificationCard: FC<CardProperties> = ({
</CardHeader>
<CardContent className="grid gap-4 p-4 pt-0 sm:p-6 sm:pt-0">
<div className="flex items-center space-x-4 rounded-md border p-2 sm:p-4">
<BellRing />
<BellRing size={16} />
<div className="flex-1 space-y-1">
<p className="text-sm font-medium leading-none">
Push Notifications
Expand All @@ -53,7 +63,13 @@ const UnreadNotificationCard: FC<CardProperties> = ({
Send notifications to device.
</p>
</div>
<Switch />
<Switch
checked={settings.mobile_push_notifications}
onCheckedChange={() =>
handleToggleSwitch("mobile_push_notifications")
}
name="mobile_push_notifications"
/>
</div>
<div data-testid="previewBody">
{notificationsPreview.map((preview, index) => (
Expand Down Expand Up @@ -86,6 +102,9 @@ const UnreadNotificationCard: FC<CardProperties> = ({
variant="primary"
isDisabled={unreadCount === 0}
className="w-full bg-primary"
onClick={() => {
// MARK ALL NOTIFICATION LOGIC
}}
>
Mark all as read
</CustomButton>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use client";

import { EllipsisVertical, Eye, Redo, Undo } from "lucide-react";

import { Button } from "~/components/common/common-button";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const navlinks = [
const UserNavbar = () => {
const pathname = usePathname();
const currentPath = pathname?.split("/")[2];

return (
<nav
className="bg-white px-5 py-2.5 md:left-[220px] lg:left-[252px]"
Expand All @@ -68,7 +69,7 @@ const UserNavbar = () => {
))}
</div>
</div>
<div className="flex items-center justify-between gap-2 bg-[#FDFDFD]">
<div className="flex items-center justify-between gap-[2rem] bg-[#FDFDFD]">
<div className="flex h-10 items-center justify-between gap-2 rounded-[6px] border border-border bg-white px-3 text-sm font-normal placeholder:text-sm">
<SearchIcon
data-testid="search"
Expand Down
2 changes: 1 addition & 1 deletion src/app/dashboard/(user-dashboard)/settings/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const layout: FC<Iproperties> = ({ children }) => {
return (
<div className="grid grid-cols-[auto_1fr]">
<SettingsSidebar />
<div className="mx-[41px] my-[30px] 2xl:mx-auto 2xl:max-w-[975px]">
<div className="my-[30px] md:mx-[41px] 2xl:mx-auto 2xl:max-w-[975px]">
{children}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { Separator } from "~/components/ui/separator";

interface IProperties {
notificationTitle: string;
}

const NotificationHeader = ({ notificationTitle }: IProperties) => {
return (
<h4 className="mb-[17px] text-[24px] font-[700]">{notificationTitle}</h4>
<header className="mb-[17px] text-[18px] font-[700] md:text-[24px]">
<h4 className="mb-[5px] px-[24px] md:px-0">{notificationTitle}</h4>
<Separator className="bg-[#BCBCBC66] md:hidden" />
</header>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,35 @@
import { Switch } from "~/components/ui/switch";
import { notificationSettingsProperties } from "../types/notification-settings.types";

interface IProperties {
title: string;
description: string;
name: keyof notificationSettingsProperties;
isChecked: boolean;
onToggle: (name: keyof notificationSettingsProperties) => void;
className?: string; // Add className as an optional property
}

const NotificationSwitchBox = ({ title, description }: IProperties) => {
export const NotificationSwitchBox = ({
title,
description,
name,
isChecked,
onToggle,
}: IProperties) => {
return (
<section className="flex w-full items-center justify-between">
<div className="w-[55%]">
<p className="mb-[8px] font-[600]">{title}</p>
<p className="text-[14px] text-neutral-dark-1">{description}</p>
<section className="flex w-full items-center justify-between md:gap-[5rem] lg:gap-[15rem] xl:gap-[25rem]">
<div className="mx-[24px] md:mx-0">
<p className="mb-[8px] text-[12px] font-[600] md:text-[16px]">
{title}
</p>
<p className="text-[10px] text-neutral-dark-1 md:text-[14px]">
{description}
</p>
</div>
<div>
<Switch />
<Switch checked={isChecked} onCheckedChange={() => onToggle(name)} />
</div>
</section>
);
};

export default NotificationSwitchBox;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import create from "zustand";

import { notificationSettingsProperties } from "../types/notification-settings.types";

// Define the Zustand store
interface NotificationStore {
settings: notificationSettingsProperties;
updateSettings: (
newSettings: Partial<notificationSettingsProperties>,
) => void;
}

export const useNotificationStore = create<NotificationStore>((set) => ({
settings: {
mobile_push_notifications: false,
email_notification_activity_in_workspace: false,
email_notification_always_send_email_notifications: false,
email_notification_email_digest: false,
email_notification_announcement_and_update_emails: false,
slack_notifications_activity_on_your_workspace: false,
slack_notifications_always_send_email_notifications: false,
slack_notifications_announcement_and_update_emails: false,
},
updateSettings: (newSettings: Partial<notificationSettingsProperties>) =>
set((state) => ({
settings: { ...state.settings, ...newSettings },
})),
}));
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import axios from "axios";

/**
* THIS API IMPLEMENTATION ARE NOT WORKING CURRENTLY, THE BACKEND WOULD BE INTEGRTED SHORTLY. ☺️
*/

const notification_id = undefined;

export const createNotification = async () => {
const data = {
message: `Welcome to HNGi8`,
};
try {
await axios.post("/notifications", data);
} catch (error) {
return error;
}
};

export const RetrieveUserNotificationSettings = async () => {
try {
await axios.get("/notification-settings");
} catch (error) {
return error;
}
};

export const updateUserNotificationSettings = async (settings: object) => {
try {
await axios.patch("/notification-settings", settings);
} catch (error) {
return error;
}
};

export const RetrieveUserNotificationAll = async () => {
try {
await axios.get("/notifications");
} catch (error) {
return error;
}
};

export const RetrieveUserUnreadNotification = async () => {
try {
await axios.get("/notifications?_read=false");
} catch (error) {
return error;
}
};

export const markNotificationAsRead = async () => {
try {
await axios.patch(`/notifications/${notification_id}`);
} catch (error) {
return error;
}
};

export const markAllNotificationAsRead = async () => {
try {
await axios.patch("/notifications");
} catch (error) {
return error;
}
};
Loading
Loading