From 72d0c250f59bfb607fdd63ba0d750a30509800dc Mon Sep 17 00:00:00 2001
From: Maciej Gierada
Date: Thu, 20 Jun 2024 14:58:31 +0200
Subject: [PATCH] feat: add ohno button
---
ui/package-lock.json | 78 +++++++++++++++++++++++-
ui/package.json | 4 +-
ui/src/app/layout.js | 9 ++-
ui/src/app/page.js | 8 ++-
ui/src/components/ActionButton/index.jsx | 39 ++++++++++++
ui/src/components/ui/sonner.jsx | 29 +++++++++
ui/src/utils/helper.js | 20 ++++++
7 files changed, 181 insertions(+), 6 deletions(-)
create mode 100644 ui/src/components/ActionButton/index.jsx
create mode 100644 ui/src/components/ui/sonner.jsx
create mode 100644 ui/src/utils/helper.js
diff --git a/ui/package-lock.json b/ui/package-lock.json
index d22d4df..0e2c6af 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -9,16 +9,18 @@
"version": "0.1.0",
"dependencies": {
"@radix-ui/react-popover": "^1.0.7",
- "@radix-ui/react-slot": "^1.0.2",
+ "@radix-ui/react-slot": "^1.1.0",
"axios": "1.7.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"date-fns": "^3.6.0",
"lucide-react": "^0.394.0",
"next": "14.2.4",
+ "next-themes": "^0.3.0",
"react": "^18",
"react-day-picker": "^8.10.1",
"react-dom": "^18",
+ "sonner": "^1.5.0",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7"
},
@@ -684,6 +686,25 @@
}
}
},
+ "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
+ "integrity": "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-compose-refs": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-popper": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.3.tgz",
@@ -790,7 +811,7 @@
}
}
},
- "node_modules/@radix-ui/react-slot": {
+ "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
"integrity": "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==",
@@ -809,6 +830,39 @@
}
}
},
+ "node_modules/@radix-ui/react-slot": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
+ "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-slot/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz",
+ "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-use-callback-ref": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz",
@@ -3966,6 +4020,16 @@
}
}
},
+ "node_modules/next-themes": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz",
+ "integrity": "sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8 || ^17 || ^18",
+ "react-dom": "^16.8 || ^17 || ^18"
+ }
+ },
"node_modules/next/node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
@@ -4980,6 +5044,16 @@
"node": ">=8"
}
},
+ "node_modules/sonner": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.5.0.tgz",
+ "integrity": "sha512-FBjhG/gnnbN6FY0jaNnqZOMmB73R+5IiyYAw8yBj7L54ER7HB3fOSE5OFiQiE2iXWxeXKvg6fIP4LtVppHEdJA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
diff --git a/ui/package.json b/ui/package.json
index 4fb5817..7077c21 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -11,16 +11,18 @@
},
"dependencies": {
"@radix-ui/react-popover": "^1.0.7",
- "@radix-ui/react-slot": "^1.0.2",
+ "@radix-ui/react-slot": "^1.1.0",
"axios": "1.7.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"date-fns": "^3.6.0",
"lucide-react": "^0.394.0",
"next": "14.2.4",
+ "next-themes": "^0.3.0",
"react": "^18",
"react-day-picker": "^8.10.1",
"react-dom": "^18",
+ "sonner": "^1.5.0",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7"
},
diff --git a/ui/src/app/layout.js b/ui/src/app/layout.js
index 8d402bc..96a939d 100644
--- a/ui/src/app/layout.js
+++ b/ui/src/app/layout.js
@@ -1,9 +1,10 @@
"use client"; // Add this line to indicate the file is a client component
-import { Inter } from "next/font/google";
import "./globals.css";
import { useEffect } from "react";
+import { Toaster } from "@/components/ui/sonner";
+
export default function RootLayout({ children }) {
useEffect(() => {
document.documentElement.classList.add("dark");
@@ -11,7 +12,11 @@ export default function RootLayout({ children }) {
return (
- {children}
+
+
+ {children}
+
+
);
}
diff --git a/ui/src/app/page.js b/ui/src/app/page.js
index 8bb0f49..ae4cb58 100644
--- a/ui/src/app/page.js
+++ b/ui/src/app/page.js
@@ -2,6 +2,7 @@ import CounterDisplay from "@/components/CounterDisplay";
import Callendar from "@/components/Callendar";
import { DisplayCard } from "@/components/Card";
import HealthStatus from "@/components/HealthStatus";
+import { ActionButton } from "@/components/ActionButton";
/**
* @typedef {Object} CounterApiResponse
@@ -114,7 +115,12 @@ const Home = async () => {
Click dates to see the details.
-
+
);
};
diff --git a/ui/src/components/ActionButton/index.jsx b/ui/src/components/ActionButton/index.jsx
new file mode 100644
index 0000000..c9f6f22
--- /dev/null
+++ b/ui/src/components/ActionButton/index.jsx
@@ -0,0 +1,39 @@
+"use client";
+import { toast } from "sonner";
+
+import { Button } from "@/components/ui/button";
+import formatCurrentDate from "@/utils/helper";
+
+/**
+ * @typedef {Object} ActionButtonProps
+ * @property {string} toast_message - the message to be displayed on on the toast popup
+ * @property {string} cta_button - the call to action to be displayed on the button
+ */
+
+/**
+ * ActionButton component
+ * @param {ActionButtonProps} actionButtonProps
+ * @returns {JSX.Element}
+ */
+export function ActionButton({ toast_message, cta_button }) {
+ return (
+
+ );
+}
diff --git a/ui/src/components/ui/sonner.jsx b/ui/src/components/ui/sonner.jsx
new file mode 100644
index 0000000..bd51a92
--- /dev/null
+++ b/ui/src/components/ui/sonner.jsx
@@ -0,0 +1,29 @@
+"use client";
+import { useTheme } from "next-themes"
+import { Toaster as Sonner } from "sonner"
+
+const Toaster = ({
+ ...props
+}) => {
+ const { theme = "system" } = useTheme()
+
+ return (
+ ()
+ );
+}
+
+export { Toaster }
diff --git a/ui/src/utils/helper.js b/ui/src/utils/helper.js
new file mode 100644
index 0000000..ae343ce
--- /dev/null
+++ b/ui/src/utils/helper.js
@@ -0,0 +1,20 @@
+/*
+ * This function formats the current date and time in a human-readable format.
+ * @returns {string} formattedNow - The formatted date and time in the following format
+ * Thursday, June 20 at 2024 at 2:41 PM
+ */
+const formatCurrentDate = () => {
+ const options = {
+ weekday: "long",
+ year: "numeric",
+ month: "long",
+ day: "2-digit",
+ hour: "numeric",
+ minute: "2-digit",
+ hour12: true,
+ };
+ const now = new Date();
+ return now.toLocaleString("en-US", options).replace(/,([^,]*)$/, " at$1");
+};
+
+export default formatCurrentDate;