diff --git a/app/aboutus/page.tsx b/app/aboutus/page.tsx new file mode 100644 index 0000000..ddd4206 --- /dev/null +++ b/app/aboutus/page.tsx @@ -0,0 +1,41 @@ +import React from 'react' +import ResponsiveNav from "@/components/Navbar/ResponsiveNav"; +import { fetchCourses, fetchSettings, fetchAboutus } from "@/utils"; +import { CoursesProps, AboutusProps } from "@/types"; +import Course from '@/components/Course/Course'; +import dynamic from 'next/dynamic' +import Home from '@/components/Aboutus/Home'; +async function getCourses() { + const courses = await fetchCourses(); + return courses; +} + +async function getAboutus() { + const aboutus: AboutusProps[] = await fetchAboutus(); + return aboutus; +} + +async function getSettings() { + const settings = await fetchSettings(); + return settings; +} + +export const metadata = { + title: "All In One", + description: "**", +} + +export default async function Page({ params }: { params: { slug: string } }) { + const courses = await getCourses(); + const settings = await getSettings(); + const aboutus = await getAboutus(); + //const course = await getCourse(params.slug); + + return ( +
+ + + +
+ ) +} \ No newline at end of file diff --git a/app/courses/[slug]/page.tsx b/app/courses/[slug]/page.tsx index 7dfc217..fb3e824 100644 --- a/app/courses/[slug]/page.tsx +++ b/app/courses/[slug]/page.tsx @@ -37,7 +37,7 @@ export default async function Page({ params }: { params: { slug: string } }) { return (
- +
) } \ No newline at end of file diff --git a/components/Aboutus/AboutusContent.tsx b/components/Aboutus/AboutusContent.tsx new file mode 100644 index 0000000..612a8ca --- /dev/null +++ b/components/Aboutus/AboutusContent.tsx @@ -0,0 +1,102 @@ +import React from 'react' +import { CoursesProps, AboutusProps } from '@/types' +const AboutusContent = ({ aboutus }: { aboutus: AboutusProps[] }) => { + return ( +
+ { + aboutus.map((item, index) => { + const isEven = index % 2 === 0; + return ( +
+
+ {isEven ? ( +
+
+ Course Image +
+
+
+

+ {item.title} +

+ {/*

+ {item.description} +

*/} +
+ +
+
+
+ ) : ( +
+
+
+

+ {item.title} +

+ {/*

+ {item.description} +

*/} +
+ +
+
+
+ Course Image +
+
+ + )} + +
+
+
+ Course Image +
+
+

+ {item.title} +

+ {/*

+ {item.description} +

*/} +
+ +
+ +
+
+ ) + }) + } + + +
+ ) +} + +export default AboutusContent diff --git a/components/Aboutus/Banner.tsx b/components/Aboutus/Banner.tsx new file mode 100644 index 0000000..90ebc27 --- /dev/null +++ b/components/Aboutus/Banner.tsx @@ -0,0 +1,28 @@ +import React from 'react' +import { CoursesProps } from '@/types' +const Banner = () => { + + return ( +
+ + +
+

+ {"關於我們"} +

+ +
+ {/*
*/} +
+ piano1 +
+
+ +
+ ) +} +export default Banner diff --git a/components/Aboutus/Home.tsx b/components/Aboutus/Home.tsx new file mode 100644 index 0000000..67ac8f2 --- /dev/null +++ b/components/Aboutus/Home.tsx @@ -0,0 +1,47 @@ +"use client"; + +import { useState, useEffect, lazy, Suspense } from "react"; +import Loading from '../Loading' +import Footer from '../Footer' +import ContactForm from "../ContactForm"; +import AboutusContent from "./AboutusContent"; +import Banner from "./Banner"; +import Map from "./Map"; +import { CoursesArrayProps, CoursesProps, SettingsProps, AboutusProps } from "@/types"; +import Whatsapp from "../Whatsapp"; +const Home = ({ courses, settings, aboutus }: { courses: CoursesProps[], settings: SettingsProps, aboutus: AboutusProps[] }) => { + const [loading, setLoading] = useState(true); + // const [courses, setCourses] = useState([]); + + useEffect(() => { + const loadCourses = async () => { + setLoading(true); + await new Promise(resolve => setTimeout(resolve, 300)); // 0.5 second delay + setLoading(false); + }; loadCourses(); + }, []); + + const startLoading = () => setLoading(true); + const stopLoading = () => setLoading(false); + + return ( +
+ {loading ? ( +
+ Loading...
}> + + +
+ ) : ( +
+ + + + +
+
+ )} +
+ ) +} +export default Home \ No newline at end of file diff --git a/components/Aboutus/Map.tsx b/components/Aboutus/Map.tsx new file mode 100644 index 0000000..35ab2d4 --- /dev/null +++ b/components/Aboutus/Map.tsx @@ -0,0 +1,96 @@ +"use client" +import React,{useEffect} from 'react' +import { GoogleMap, LoadScript, Marker } from '@react-google-maps/api'; +import Loading from '../Loading' +import Link from 'next/link' +import { SettingsProps } from '@/types'; +import { HiLocationMarker } from "react-icons/hi"; +import { MdEmail } from "react-icons/md"; +import { FaPhone } from "react-icons/fa6"; +import mailgo from "mailgo"; +const containerStyle = { + width: '100%', + height: '100%' +}; +const Map = ({ settings }: { settings: SettingsProps }) => { + const center = { + lat: settings.latitude, + lng: settings.longitude, + }; + + useEffect(() => { + mailgo(); + }, []); + + return ( +
+
+ }> + + + + +
+
+
+
+
+ +
+
+

+ {"地址"} +

+ +
+ +
+
+
+ +
+
+

+ {"電郵"} +

+ +

+ {settings.email} +

+ +
+ +
+
+ +
+ +
+
+

+ {"電話"} +

+ +

+ {settings.phone} +

+ +
+ +
+
+
+
+ ) +} + +export default Map diff --git a/components/Course/Accordion.tsx b/components/Course/Accordion.tsx index 9b0db75..bd2d638 100644 --- a/components/Course/Accordion.tsx +++ b/components/Course/Accordion.tsx @@ -34,72 +34,6 @@ async function reorganizedSchedule(schedule: ScheduleProps[]) { const Accordion = async ({ courseData }: { courseData: CoursesProps }) => { const newSchedule = await reorganizedSchedule(courseData.schedule) - const fakeData = [ - { - "yearAndMonth": "2024年10月", - "schedule": [ - { - "info2": "A room, 14F, Sha Tin Market, N.T.", - "info1": "11:00-12:00, 13:00-14:00, 15:00-16:00, 17:00-18:00", - "id": "e19a7934-82fe-4027-aca6-57a419e9623e", - "title": "A班", - "date": "2024-10-05T01:30:00Z", - "course_id": "29ab193d-2927-459d-9277-5520771b2dd6" - }, - { - "info2": "Room B, Sheung Shui Village, N.T.", - "info1": "11:00-12:00, 13:00-14:00, 15:00-16:00, 17:00-18:00", - "id": "dc49a1b6-1c1f-44d6-bc52-b757aeba7b5b", - "title": "B班", - "date": "2024-10-05T01:31:00Z", - "course_id": "29ab193d-2927-459d-9277-5520771b2dd6" - }, - { - "info2": "Room B, Sheung Shui Village, N.T.", - "info1": "11:00-12:00, 13:00-14:00, 15:00-16:00, 17:00-18:00", - "id": "d4785a90-311b-4a91-8fb7-beb077245f4f", - "title": "A班", - "date": "2024-10-06T01:31:00Z", - "course_id": "29ab193d-2927-459d-9277-5520771b2dd6" - } - ] - }, - { - "yearAndMonth": "2024年11月", - "schedule": [ - { - "info2": "Room B, Sheung Shui Village, N.T.", - "info1": "11:00-12:00, 13:00-14:00, 15:00-16:00, 17:00-18:00", - "id": "5c88b2a7-6b4d-455f-b341-1fec3173d208", - "title": "A班", - "date": "2024-11-06T01:31:00Z", - "course_id": "29ab193d-2927-459d-9277-5520771b2dd6" - } - ] - }, - { - "yearAndMonth": "2025年01月", - "schedule": [ - { - "info2": "Room B, Sheung Shui Village, N.T.", - "info1": "11:00-12:00, 13:00-14:00, 15:00-16:00, 17:00-18:00", - "id": "8a30dec2-63ed-4237-8f5b-177c42f29dda", - "title": "B班", - "date": "2025-01-04T01:31:00Z", - "course_id": "29ab193d-2927-459d-9277-5520771b2dd6" - }, - { - "info2": "Room B, Sheung Shui Village, N.T.", - "info1": "11:00-12:00, 13:00-14:00, 15:00-16:00, 17:00-18:00", - "id": "86ddf906-499b-4dbd-967d-cc4dddd9f27b", - "title": "A班", - "date": "2025-01-05T01:31:00Z", - "course_id": "29ab193d-2927-459d-9277-5520771b2dd6" - } - ] - } - ] - console.log(newSchedule) return (
@@ -109,7 +43,7 @@ const Accordion = async ({ courseData }: { courseData: CoursesProps }) => { {"課程時間表"}

{ - fakeData.map((item, index) => { + newSchedule.map((item, index) => { return ( ) diff --git a/components/Course/Course.tsx b/components/Course/Course.tsx index 6c9cd98..ddb529f 100644 --- a/components/Course/Course.tsx +++ b/components/Course/Course.tsx @@ -1,18 +1,47 @@ -import React from 'react' +"use client" +import React, { useEffect, useState, lazy, Suspense } from 'react' import Banner from './Banner' import LongDesc from './LongDesc' import CourseImagesSilder from './CourseImagesSilder' import Accordion from './Accordion' -import { CoursesProps } from '@/types' +import { CoursesProps, SettingsProps } from '@/types' import Footer from '../Footer' -const Course = ({ course }: { course: CoursesProps }) => { +import Loading from '../Loading' + +const Course = ({ course, settings }: { course: CoursesProps, settings: SettingsProps }) => { + + const [loading, setLoading] = useState(true); + // const [courses, setCourses] = useState([]); + + useEffect(() => { + const loadCourses = async () => { + setLoading(true); + await new Promise(resolve => setTimeout(resolve, 300)); // 0.5 second delay + setLoading(false); + }; loadCourses(); + }, []); + + const startLoading = () => setLoading(true); + const stopLoading = () => setLoading(false); + + return (
- - - - -
+ {loading ? ( +
+ Loading...
}> + + +
+ ) : ( +
+ + + + +
+
+ )}
) } diff --git a/components/Navbar/MobileNav.tsx b/components/Navbar/MobileNav.tsx index 13c90ee..b45b1b1 100644 --- a/components/Navbar/MobileNav.tsx +++ b/components/Navbar/MobileNav.tsx @@ -67,7 +67,7 @@ const MobileNav = ({ closeNav, showNav, courses }: Props) => {
- +

關於我們

diff --git a/components/Navbar/Nav.tsx b/components/Navbar/Nav.tsx index b94759b..334ee81 100644 --- a/components/Navbar/Nav.tsx +++ b/components/Navbar/Nav.tsx @@ -81,7 +81,7 @@ const Nav = ({ openNav, courses, showNav, settings }: Props) => {
)}
- +

{"關於我們"}

@@ -93,7 +93,7 @@ const Nav = ({ openNav, courses, showNav, settings }: Props) => {
window.open(settings.facebook)} > + onClick={() => window.open(settings.facebook)} > diff --git a/package-lock.json b/package-lock.json index 2761522..f1e2715 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "webfrontend", "version": "0.1.0", "dependencies": { + "@react-google-maps/api": "^2.19.3", "animate.css": "^4.1.1", "clsx": "^2.1.1", "dotenv": "^16.4.5", @@ -15,6 +16,7 @@ "framer-motion": "^11.7.0", "gsap": "^3.12.5", "keen-slider": "^6.8.6", + "mailgo": "^0.12.2", "moment": "^2.30.1", "next": "14.2.13", "nextjs-cors": "^2.2.0", @@ -137,6 +139,25 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@googlemaps/js-api-loader": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.16.2.tgz", + "integrity": "sha512-psGw5u0QM6humao48Hn4lrChOM2/rA43ZCm3tKK9qQsEj1/VzqkCqnvGfEOshDbBQflydfaRovbKwZMF4AyqbA==", + "license": "Apache-2.0", + "dependencies": { + "fast-deep-equal": "^3.1.3" + } + }, + "node_modules/@googlemaps/markerclusterer": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@googlemaps/markerclusterer/-/markerclusterer-2.5.3.tgz", + "integrity": "sha512-x7lX0R5yYOoiNectr10wLgCBasNcXFHiADIBdmn7jQllF2B5ENQw5XtZK+hIw4xnV0Df0xhN4LN98XqA5jaiOw==", + "license": "Apache-2.0", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "supercluster": "^8.0.1" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -494,6 +515,36 @@ "node": ">=14" } }, + "node_modules/@react-google-maps/api": { + "version": "2.19.3", + "resolved": "https://registry.npmjs.org/@react-google-maps/api/-/api-2.19.3.tgz", + "integrity": "sha512-jiLqvuOt5lOowkLeq7d077AByTyJp+s6hZVlLhlq7SBacBD37aUNpXBz2OsazfeR6Aw4a+9RRhAEjEFvrR1f5A==", + "license": "MIT", + "dependencies": { + "@googlemaps/js-api-loader": "1.16.2", + "@googlemaps/markerclusterer": "2.5.3", + "@react-google-maps/infobox": "2.19.2", + "@react-google-maps/marker-clusterer": "2.19.2", + "@types/google.maps": "3.55.2", + "invariant": "2.2.4" + }, + "peerDependencies": { + "react": "^16.8 || ^17 || ^18", + "react-dom": "^16.8 || ^17 || ^18" + } + }, + "node_modules/@react-google-maps/infobox": { + "version": "2.19.2", + "resolved": "https://registry.npmjs.org/@react-google-maps/infobox/-/infobox-2.19.2.tgz", + "integrity": "sha512-6wvBqeJsQ/eFSvoxg+9VoncQvNoVCdmxzxRpLvmjPD+nNC6mHM0vJH1xSqaKijkMrfLJT0nfkTGpovrF896jwg==", + "license": "MIT" + }, + "node_modules/@react-google-maps/marker-clusterer": { + "version": "2.19.2", + "resolved": "https://registry.npmjs.org/@react-google-maps/marker-clusterer/-/marker-clusterer-2.19.2.tgz", + "integrity": "sha512-x9ibmsP0ZVqzyCo1Pitbw+4b6iEXRw/r1TCy3vOUR3eKrzWLnHYZMR325BkZW2r8fnuWE/V3Fp4QZOP9qYORCw==", + "license": "MIT" + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -524,6 +575,12 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/google.maps": { + "version": "3.55.2", + "resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.55.2.tgz", + "integrity": "sha512-JcTwzkxskR8DN/nnX96Pie3gGN3WHiPpuxzuQ9z3516o1bB243d8w8DHUJ8BohuzoT1o3HUFta2ns/mkZC8KRw==", + "license": "MIT" + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -2348,7 +2405,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, "license": "MIT" }, "node_modules/fast-glob": { @@ -2929,6 +2985,15 @@ "node": ">= 0.4" } }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -3496,6 +3561,12 @@ "node": ">=4.0" } }, + "node_modules/kdbush": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz", + "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==", + "license": "ISC" + }, "node_modules/keen-slider": { "version": "6.8.6", "resolved": "https://registry.npmjs.org/keen-slider/-/keen-slider-6.8.6.tgz", @@ -3617,6 +3688,17 @@ "dev": true, "license": "ISC" }, + "node_modules/mailgo": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/mailgo/-/mailgo-0.12.2.tgz", + "integrity": "sha512-iX4F3eOhPJ+12YlM51UNV8yTYwxHywaGP1C9Qaep/iNP2ZS+xzqHR7U3o+7HoCL19gZKysc7+MwgBEiRy8ogzA==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mailgo" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -5214,6 +5296,15 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/supercluster": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz", + "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", + "license": "ISC", + "dependencies": { + "kdbush": "^4.0.2" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", diff --git a/package.json b/package.json index 2fd555a..6ad3ed9 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "lint": "next lint" }, "dependencies": { + "@react-google-maps/api": "^2.19.3", "animate.css": "^4.1.1", "clsx": "^2.1.1", "dotenv": "^16.4.5", @@ -16,6 +17,7 @@ "framer-motion": "^11.7.0", "gsap": "^3.12.5", "keen-slider": "^6.8.6", + "mailgo": "^0.12.2", "moment": "^2.30.1", "next": "14.2.13", "nextjs-cors": "^2.2.0", diff --git a/public/images/piano1.jpg b/public/images/piano1.jpg new file mode 100644 index 0000000..aba73d2 Binary files /dev/null and b/public/images/piano1.jpg differ diff --git a/public/images/smalllogo.png b/public/images/smalllogo.png new file mode 100644 index 0000000..04fa867 Binary files /dev/null and b/public/images/smalllogo.png differ diff --git a/types/index.ts b/types/index.ts index 9e5fb53..0a574b5 100644 --- a/types/index.ts +++ b/types/index.ts @@ -17,6 +17,14 @@ export interface SettingsProps { } +export interface AboutusProps { + id: string; + title: string; + description: string + image: string; + index: number; +} + export interface MessageProps { name: string, phone: string, diff --git a/utils/index.ts b/utils/index.ts index 1b47827..166146d 100644 --- a/utils/index.ts +++ b/utils/index.ts @@ -1,5 +1,5 @@ -import { CoursesProps, CoursesArrayProps, SettingsProps, MessageProps } from "@/types"; +import { CoursesProps, CoursesArrayProps, SettingsProps, MessageProps, AboutusProps } from "@/types"; @@ -37,6 +37,30 @@ export async function postMessage(data: MessageProps) { } } +export async function fetchAboutus() { + const headers: HeadersInit = { + accept: "application/json" + }; + const url = `${process.env.api_url}aboutUs`; + console.log('Fetching from URL:', url); + try { + const response = await fetch(url, { headers }); + console.log('Response status:', response.status); + const result = await response.json(); + console.log('Fetched data:', result); + + // Sort the result by index + const sortedResult: AboutusProps[] = result.data.sort((a: any, b: any) => a.index - b.index); + + return sortedResult; + } + catch (error) { + console.error('Fetch error:', error); + throw error; + } +} + + export async function fetchCourses() { const headers: HeadersInit = {