-
Notifications
You must be signed in to change notification settings - Fork 1
Feature/app setting panel notifications #43
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
base: dev
Are you sure you want to change the base?
Changes from 9 commits
c72947c
9218af1
9f1f8cc
21cde4f
9558b72
351fe2c
06d6d59
7c9675c
e909566
4a8ca41
21f5763
95e6da6
5405501
f10d0bb
7b16626
a8db91f
639598c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hej |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| export interface AppNotificationConfig { | ||
| id: string; | ||
| title: string; | ||
| } | ||
|
|
||
| export const NOTIFICATIONS: AppNotificationConfig[] = [ | ||
| { id: "1", title: "Cykliczne powiadomienie ⏰" }, | ||
| { id: "2", title: "Czas na przerwę! ☕" }, | ||
| { id: "3", title: "Czas na ćwiczenie! 🔵" }, | ||
| { id: "4", title: "Zadbaj o nawodnienie! 💧" }, | ||
| ]; | ||
|
|
||
| // Mapowanie tytułu na id – używane w useNotifications | ||
| export const NOTIFICATION_TITLE_TO_ID: Record<string, string> = Object.fromEntries( | ||
| NOTIFICATIONS.map((n) => [n.title, n.id]) | ||
| ); | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| import { Bell, SquareArrowLeft } from "lucide-react"; | ||
| import { useState } from "react"; | ||
| import { Link } from "react-router-dom"; | ||
| import Cookies from "js-cookie"; | ||
| import { NOTIFICATIONS } from "../lib/notificationConfig"; | ||
|
|
||
|
|
||
| interface UstawieniaPowiadomien { | ||
| id: string; | ||
| title: string; | ||
| active: boolean; | ||
| icon: React.ReactNode; | ||
| } | ||
|
|
||
| const COOKIE_KEY = "user_notifications_preferences"; | ||
|
|
||
| function Powiadomienia() { | ||
|
|
||
| // Stan przechowujący wybory użytkownika | ||
| const [settings, setSettings] = useState<UstawieniaPowiadomien[]>(() => { | ||
| const savedCookies = Cookies.get(COOKIE_KEY); | ||
|
|
||
| const defaultSettings = NOTIFICATIONS.map((n) => ({ | ||
| ...n, | ||
| active: true, | ||
| icon: <Bell size={17} />, | ||
| })); | ||
|
|
||
|
|
||
| if (savedCookies) { | ||
| try { | ||
| const parsed = JSON.parse(savedCookies); | ||
| // Łączymy ikony z zapisanymi stanami powiadomien | ||
| return defaultSettings.map(ds => ({ | ||
| ...ds, | ||
| active: parsed[ds.id] ?? ds.active | ||
| })); | ||
| } catch (error) { | ||
| // W przypadku wystąpienia błędu przy cookies, ustawiamy domyśne ustawienia | ||
| console.error("Błąd podczas odczytywania cookies:", error); // wyswietlenie bledu | ||
| return defaultSettings; | ||
| } | ||
| } | ||
| return defaultSettings; | ||
| }); | ||
|
|
||
| // Funkcja przełączająca stan konkretnego powiadomienia i zapisująca nowy stan do COOKIES | ||
| const toggle = (id: string) => { | ||
| const newSettings = settings.map(item => | ||
| item.id === id ? { ...item, active: !item.active } : item | ||
| ); | ||
|
|
||
| setSettings(newSettings); | ||
|
|
||
|
|
||
| // Zapisywanie uproszczonego obiektu do COOKIES {id, active} | ||
| const configToSave = newSettings.reduce((acc, curr) => ({ | ||
| ...acc, [curr.id]: curr.active | ||
| }), {}); | ||
|
|
||
| // Po 365 dniach COOKIES zostaje usuniete | ||
| Cookies.set(COOKIE_KEY, JSON.stringify(configToSave), { expires: 365 }); | ||
| }; | ||
|
|
||
| return ( | ||
| <div className="min-h-screen w-full bg-gray-100 flex flex-col items-center p-10 relative"> | ||
|
|
||
| {/* Przycisk powrotu */} | ||
| <Link | ||
| to="/Ustawienia" | ||
| className="absolute left-6 top-10 p-3 bg-white text-black rounded-full shadow-lg active:scale-95 transition-all hover:bg-gray-50" | ||
| > | ||
| <SquareArrowLeft size={20} /> | ||
| </Link> | ||
|
|
||
| {/* Nagłówek strony */} | ||
| <div className="w-full max-w-md flex items-center mb-8"> | ||
| <h1 className="text-4xl font-bold text-gray-800">Powiadomienia</h1> | ||
| </div> | ||
|
|
||
| {/* Lista opcji do wyboru */} | ||
| <div className="w-full max-w-md space-y-3"> | ||
| {settings.map((item) => ( | ||
| <div | ||
| key={item.id} | ||
| onClick={() => toggle(item.id)} | ||
| className="flex items-center justify-between p-4 bg-white rounded-2xl shadow-sm cursor-pointer active:bg-gray-50 transition-colors" | ||
| > | ||
| {/* Ikonka i naglowek powiadomienia */} | ||
| <div className="flex items-center gap-4"> | ||
| <div className="p-2 bg-blue-50 text-blue-600 rounded-lg"> | ||
| {item.icon} | ||
| </div> | ||
|
|
||
| <span className="font-medium text-gray-600"> | ||
| {item.title}</span> | ||
| </div> | ||
|
|
||
| {/* Toggle - przycisk switch */} | ||
| <div className={`w-12 h-6 rounded-full transition-colors relative ${item.active ? 'bg-green-500' : 'bg-gray-300'}`}> | ||
| <div className={`absolute top-1 w-4 h-4 bg-white rounded-full transition-all ${item.active ? 'left-7' : 'left-1'}`} /> | ||
| </div> | ||
| </div> | ||
| ))} | ||
| </div> | ||
|
|
||
| <div className="mt-auto mb-6 text-gray-400 text-sm text-center px-4"> | ||
| Powiadomienia zostały włączone | ||
| </div> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Czy tego jakoś specjalnie potrzebujemy? Wydaje mi się, że lepiej byłoby gdzieś tutaj na tej stronie wykrywać, czy mamy dostęp do Push API, a jak nie, zamiast całych ustawień wyświetlać przycisk, który uruchomiłby prompta o zgodę na powiadomienia |
||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| export default Powiadomienia | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,19 @@ | ||
| import { Link } from "react-router-dom"; | ||
|
|
||
|
|
||
| function Ustawienia() { | ||
| return ( | ||
| <div className="min-h-screen w-full px-8 text-center bg-gray-400 flex flex-col justify-center"> | ||
| <h1 className="text-5xl font-bold">Ustawienia</h1> | ||
|
|
||
| {/* Powiadomienia */} | ||
| <Link | ||
| to="/Powiadomienia" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Trzymajmy się raczej wszędzie podobnej konwencji i róbmy |
||
| className="px-6 py-3 bg-white text-black rounded-full shadow-lg active:scale-95 transition-all font-semibold" | ||
| > | ||
| Powiadomienia | ||
| </Link> | ||
|
|
||
| </div> | ||
| ); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nie jestem pewny, czy chcemy całą nową bibliotekę do ciasteczek, jak mam gotowe natywne rozwiązania: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies