Skip to content

Commit 2c6ad02

Browse files
committed
added calendar integration
1 parent 00b5feb commit 2c6ad02

File tree

11 files changed

+155
-13
lines changed

11 files changed

+155
-13
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,7 @@ dist-ssr
2222
*.njsproj
2323
*.sln
2424
*.sw?
25+
*.env
26+
27+
# Optional manual test
28+
/test/

index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
<title>Dominika Swioklo</title>
8+
<link href="https://calendar.google.com/calendar/scheduling-button-script.css" rel="stylesheet">
89
</head>
910
<body>
1011
<div id="root"></div>
@@ -18,5 +19,6 @@
1819
})();
1920
</script>
2021
<script type="module" src="/src/main.jsx"></script>
22+
<script src="https://calendar.google.com/calendar/scheduling-button-script.js" async></script>
2123
</body>
2224
</html>

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"version": "0.0.0",
55
"type": "module",
66
"scripts": {
7-
"dev": "vite",
7+
"dev": "vite --host",
88
"build": "vite build",
99
"lint": "eslint .",
1010
"preview": "vite preview",

src/components/Navbar.css

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
display: flex;
1414
justify-content: space-between;
1515
align-items: center;
16+
flex-wrap: wrap;
1617
}
1718

1819
.nav-logo {
@@ -58,33 +59,51 @@
5859
.lang-switcher button {
5960
background: none;
6061
border: none;
61-
color: var(--text-dark);
62+
color: var(--white);
6263
cursor: pointer;
6364
font-size: 0.9rem;
6465
padding: 0.25rem 0.5rem;
6566
transition: color 0.3s;
6667
}
6768

6869
.lang-switcher button:hover {
69-
color: var(--primary-color);
70+
color: var(--white);
7071
}
7172

7273
.lang-switcher button.active {
73-
color: var(--primary-color);
74+
color: var(--white);
7475
font-weight: 600;
7576
}
7677

7778
.lang-switcher span {
78-
color: var(--text-light);
79+
color: var(--white);
7980
}
8081

8182
@media (max-width: 768px) {
82-
.nav-menu {
83+
.nav-container {
84+
padding: 1rem;
85+
flex-direction: column;
8386
gap: 1rem;
84-
font-size: 0.9rem;
8587
}
8688

87-
.nav-container {
88-
padding: 1rem;
89+
.nav-logo {
90+
width: 100%;
91+
text-align: center;
92+
}
93+
94+
.nav-menu {
95+
gap: 0.8rem;
96+
font-size: 0.85rem;
97+
flex-wrap: wrap;
98+
justify-content: center;
99+
}
100+
101+
.nav-menu li:nth-child(5) {
102+
flex-basis: 100%;
103+
text-align: center;
104+
}
105+
106+
.nav-cta {
107+
display: inline-block;
89108
}
90109
}

src/components/Navbar.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export default function Navbar() {
3131
<li><Link to="/prices">{text[language].prices}</Link></li>
3232
<li><Link to="/about">{text[language].about}</Link></li>
3333
<li><Link to="/contact">{text[language].contact}</Link></li>
34-
<li><Link to="/appointment" className="nav-cta">{text[language].appointment}</Link></li>
34+
<li><Link to="/prices" className="nav-cta">{text[language].appointment}</Link></li>
3535
<li className="lang-switcher">
3636
<button
3737
onClick={() => toggleLanguage('en')}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
.modal-overlay {
2+
position: fixed;
3+
top: 0;
4+
left: 0;
5+
right: 0;
6+
bottom: 0;
7+
background: rgba(0, 0, 0, 0.7);
8+
display: flex;
9+
align-items: center;
10+
justify-content: center;
11+
z-index: 1000;
12+
}
13+
14+
.modal-content {
15+
background: var(--white);
16+
padding: 0;
17+
border-radius: 12px;
18+
width: 80%;
19+
height: 85vh;
20+
position: relative;
21+
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
22+
overflow: hidden;
23+
}
24+
25+
.modal-close {
26+
position: absolute;
27+
top: 0.5rem;
28+
right: 0.5rem;
29+
background: var(--white);
30+
border: none;
31+
font-size: 2rem;
32+
cursor: pointer;
33+
color: var(--text-dark);
34+
line-height: 1;
35+
width: 40px;
36+
height: 40px;
37+
border-radius: 50%;
38+
display: flex;
39+
align-items: center;
40+
justify-content: center;
41+
z-index: 10;
42+
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
43+
}
44+
45+
.modal-close:hover {
46+
color: var(--primary-color);
47+
}
48+
49+
50+
51+
.calendar-iframe {
52+
width: 100%;
53+
height: 100%;
54+
border: none;
55+
border-radius: 12px;
56+
}
57+
58+
@media (max-width: 768px) {
59+
.modal-content {
60+
width: 100%;
61+
height: 100vh;
62+
border-radius: 0;
63+
}
64+
65+
.calendar-iframe {
66+
border-radius: 0;
67+
}
68+
69+
.modal-close {
70+
top: 1rem;
71+
right: 1rem;
72+
}
73+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { GOOGLE_CALENDAR_CONFIG } from '../../config/calendar';
2+
import './CalendarModal.css';
3+
4+
export default function CalendarModal({ isOpen, onClose }) {
5+
if (!isOpen) return null;
6+
7+
return (
8+
<div className="modal-overlay" onClick={onClose}>
9+
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
10+
<button className="modal-close" onClick={onClose}>×</button>
11+
<iframe
12+
src={GOOGLE_CALENDAR_CONFIG.url}
13+
className="calendar-iframe"
14+
title="Book Appointment"
15+
/>
16+
</div>
17+
</div>
18+
);
19+
}

src/config/calendar.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const GOOGLE_CALENDAR_CONFIG = {
2+
url: import.meta.env.VITE_GOOGLE_CALENDAR_BOOKING_URL,
3+
color: '#2d5f5d',
4+
label: 'Book an appointment'
5+
};

src/context/LanguageContext.jsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,22 @@ import { createContext, useContext, useState } from 'react';
33
const LanguageContext = createContext();
44

55
export function LanguageProvider({ children }) {
6-
const [language, setLanguage] = useState('en');
6+
const [language, setLanguage] = useState(() => {
7+
const browserLang = navigator.language.toLowerCase();
8+
return browserLang.startsWith('pl') ? 'pl' : 'en';
9+
});
710

811
const toggleLanguage = (lang) => {
912
setLanguage(lang);
13+
localStorage.setItem('preferredLanguage', lang);
1014
};
1115

16+
// Check for saved preference on mount
17+
useState(() => {
18+
const saved = localStorage.getItem('preferredLanguage');
19+
if (saved) setLanguage(saved);
20+
}, []);
21+
1222
return (
1323
<LanguageContext.Provider value={{ language, toggleLanguage }}>
1424
{children}

src/pages_en/Prices.jsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
import { useState } from 'react';
2+
import CalendarModal from '../components/booking/CalendarModal';
13
import './Prices.css';
24

35
export default function Prices() {
6+
const [isModalOpen, setIsModalOpen] = useState(false);
7+
48
const services = [
59
{
610
title: "Individual Therapy Session",
@@ -68,7 +72,7 @@ export default function Prices() {
6872
<li key={idx}>{feature}</li>
6973
))}
7074
</ul>
71-
<button className="book-button">Book Now</button>
75+
<button className="book-button" onClick={() => setIsModalOpen(true)}>Book Now</button>
7276
</div>
7377
))}
7478
</div>
@@ -78,6 +82,7 @@ export default function Prices() {
7882
<p>We accept most major insurance plans. Please contact us to verify your coverage. Self-pay options and sliding scale fees available upon request.</p>
7983
</div>
8084
</div>
85+
<CalendarModal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} />
8186
</div>
8287
);
8388
}

0 commit comments

Comments
 (0)