diff --git a/.env.example b/.env.example index 349d712..36f40c3 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,7 @@ -NEXT_PUBLIC_SITE_URL=https://example.com +NEXT_PUBLIC_SITE_URL=https://westsoundhall.org +STRIPE_SECRET_KEY=sk_XXXX +NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_XXXX +POSTMARK_SERVER_TOKEN=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX +FROM_ADDRESS=support@westsoundhall.org +ADMIN_ADDRESS=board@westsoundhall.org +CALENDAR_ADDR=https://calendar.google.com/calendar/ical/westsoundcommunityclub%40gmail.com/private-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/basic.ics diff --git a/README.md b/README.md index b8f03c8..2ec3d96 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,7 @@ https://westsoundhall.org ## Running -Pre-build containers are created whenever a version is tagged in this -repository. Pull the [latest -version](https://git.grosinger.net/tgrosinger/-/packages/container/west-sound-hall/) -and run on a server with Docker available. +Pre-build containers are created whenever a version is tagged in this repository. Pull the [latest version](https://git.grosinger.net/tgrosinger/-/packages/container/west-sound-hall/) and run on a server with Docker available. ```sh docker run -p 3000:3000 git.grosinger.net/tgrosinger/west-sound-hall:0.0.14 @@ -17,11 +14,11 @@ docker run -p 3000:3000 git.grosinger.net/tgrosinger/west-sound-hall:0.0.14 ## Updating -### Events on the Homepage +### Events on the Homepage and the Calendar -The homepage has a list of upcoming events. This list is created from [`src/app/upcoming-events.json`](https://git.grosinger.net/tgrosinger/west-sound-hall/src/branch/main/src/app/upcoming-events.json). To update the events listed, modify that file, tag a new version, and then update the running container to the latest version. +The events on the calendar are loaded from the westsoundcommunityclub@gmail.com Google Calendar. -Events in the past will be automatically hidden from view. +Please note that all events on the calendar will be displayed. If an event should not reveal the title to the public, add the word "Private" to the event description (not the title). ### News Posts @@ -41,11 +38,7 @@ To get started, first install the npm dependencies: npm install ``` -Next, create a `.env.local` file in the root of your project and set the `NEXT_PUBLIC_SITE_URL` variable to your site's public URL: - -``` -NEXT_PUBLIC_SITE_URL=https://example.com -``` +Next, copy the `.env.example` file from this directory and call it `.env.local`. Fill in the values that have been redacted with their actual secrets. Be sure to use the test environment key from Stripe unless you are setting up production. Next, run the development server: @@ -59,4 +52,4 @@ Finally, open [http://localhost:3000](http://localhost:3000) in your browser to This site is based off of the Spotlight template from Tailwind, and licensed under the [Tailwind UI license](https://tailwindui.com/license). -It was purchased by Tony Grosinger. +It was purchased by [Tony Grosinger](mailto:tony@grosinger.net). diff --git a/package-lock.json b/package-lock.json index 0d52947..c0f524c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,15 +18,13 @@ "@stripe/stripe-js": "2.2.1", "@tailwindcss/forms": "0.5.7", "@tailwindcss/typography": "^0.5.4", - "@types/node": "20.4.7", - "@types/react": "18.2.18", - "@types/react-dom": "18.2.7", - "@types/webpack-env": "^1.18.1", "autoprefixer": "^10.4.12", "cheerio": "^1.0.0-rc.12", "clsx": "^1.2.1", + "dayjs": "^1.11.10", "fast-glob": "^3.2.11", "feed": "^4.2.2", + "ical": "^0.8.0", "next": "13.4.16", "next-themes": "^0.2.1", "postmark": "4.0.2", @@ -39,6 +37,11 @@ "typescript": "5.1.6" }, "devDependencies": { + "@types/ical": "^0.8.3", + "@types/node": "20.4.7", + "@types/react": "18.2.18", + "@types/react-dom": "18.2.7", + "@types/webpack-env": "^1.18.1", "eslint": "8.45.0", "eslint-config-next": "13.4.16", "prettier": "^3.0.1", @@ -701,6 +704,33 @@ "@types/unist": "^2" } }, + "node_modules/@types/ical": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@types/ical/-/ical-0.8.3.tgz", + "integrity": "sha512-qPejGORaXOstmqyKzp0Qw9nXDPiWiahiJJcx4zMB0zJVg0rLfJ6bDip/naqagEqYTjKl/LI91399hR8zFwRJ5A==", + "dev": true, + "dependencies": { + "rrule": "2.6.4" + } + }, + "node_modules/@types/ical/node_modules/rrule": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.6.4.tgz", + "integrity": "sha512-sLdnh4lmjUqq8liFiOUXD5kWp/FcnbDLPwq5YAc/RrN6120XOPb86Ae5zxF7ttBVq8O3LxjjORMEit1baluahA==", + "dev": true, + "dependencies": { + "tslib": "^1.10.0" + }, + "optionalDependencies": { + "luxon": "^1.21.3" + } + }, + "node_modules/@types/ical/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/@types/json-schema": { "version": "7.0.12", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", @@ -755,6 +785,7 @@ "version": "18.2.7", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz", "integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==", + "dev": true, "dependencies": { "@types/react": "*" } @@ -772,7 +803,8 @@ "node_modules/@types/webpack-env": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.1.tgz", - "integrity": "sha512-D0HJET2/UY6k9L6y3f5BL+IDxZmPkYmPT4+qBrRdmRLYRuV0qNKizMgTvYxXZYn+36zjPeoDZAEYBCM6XB+gww==" + "integrity": "sha512-D0HJET2/UY6k9L6y3f5BL+IDxZmPkYmPT4+qBrRdmRLYRuV0qNKizMgTvYxXZYn+36zjPeoDZAEYBCM6XB+gww==", + "dev": true }, "node_modules/@typescript-eslint/parser": { "version": "5.62.0", @@ -2243,6 +2275,11 @@ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, + "node_modules/dayjs": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -3472,9 +3509,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", - "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -4110,6 +4147,14 @@ "node": ">=14.18.0" } }, + "node_modules/ical": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/ical/-/ical-0.8.0.tgz", + "integrity": "sha512-/viUSb/RGLLnlgm0lWRlPBtVeQguQRErSPYl3ugnUaKUnzQswKqOG3M8/P1v1AB5NJwlHTuvTq1cs4mpeG2rCg==", + "dependencies": { + "rrule": "2.4.1" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -5596,6 +5641,15 @@ "node": ">=10" } }, + "node_modules/luxon": { + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.1.tgz", + "integrity": "sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw==", + "optional": true, + "engines": { + "node": "*" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -6978,9 +7032,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "funding": [ { "type": "github", @@ -7644,9 +7698,9 @@ } }, "node_modules/postcss": { - "version": "8.4.27", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", - "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "funding": [ { "type": "opencollective", @@ -7662,9 +7716,9 @@ } ], "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" @@ -8388,6 +8442,14 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rrule": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.4.1.tgz", + "integrity": "sha512-+NcvhETefswZq13T8nkuEnnQ6YgUeZaqMqVbp+ZiFDPCbp3AVgQIwUvNVDdMNrP05bKZG9ddDULFp0qZZYDrxg==", + "optionalDependencies": { + "luxon": "^1.3.3" + } + }, "node_modules/run-applescript": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", @@ -8859,9 +8921,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "engines": { "node": ">=0.10.0" } @@ -10911,6 +10973,33 @@ "@types/unist": "^2" } }, + "@types/ical": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@types/ical/-/ical-0.8.3.tgz", + "integrity": "sha512-qPejGORaXOstmqyKzp0Qw9nXDPiWiahiJJcx4zMB0zJVg0rLfJ6bDip/naqagEqYTjKl/LI91399hR8zFwRJ5A==", + "dev": true, + "requires": { + "rrule": "2.6.4" + }, + "dependencies": { + "rrule": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.6.4.tgz", + "integrity": "sha512-sLdnh4lmjUqq8liFiOUXD5kWp/FcnbDLPwq5YAc/RrN6120XOPb86Ae5zxF7ttBVq8O3LxjjORMEit1baluahA==", + "dev": true, + "requires": { + "luxon": "^1.21.3", + "tslib": "^1.10.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, "@types/json-schema": { "version": "7.0.12", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", @@ -10965,6 +11054,7 @@ "version": "18.2.7", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz", "integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==", + "dev": true, "requires": { "@types/react": "*" } @@ -10982,7 +11072,8 @@ "@types/webpack-env": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.1.tgz", - "integrity": "sha512-D0HJET2/UY6k9L6y3f5BL+IDxZmPkYmPT4+qBrRdmRLYRuV0qNKizMgTvYxXZYn+36zjPeoDZAEYBCM6XB+gww==" + "integrity": "sha512-D0HJET2/UY6k9L6y3f5BL+IDxZmPkYmPT4+qBrRdmRLYRuV0qNKizMgTvYxXZYn+36zjPeoDZAEYBCM6XB+gww==", + "dev": true }, "@typescript-eslint/parser": { "version": "5.62.0", @@ -12041,6 +12132,11 @@ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, + "dayjs": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -12956,9 +13052,9 @@ "dev": true }, "follow-redirects": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", - "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==" + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" }, "for-each": { "version": "0.3.3", @@ -13400,6 +13496,14 @@ "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", "dev": true }, + "ical": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/ical/-/ical-0.8.0.tgz", + "integrity": "sha512-/viUSb/RGLLnlgm0lWRlPBtVeQguQRErSPYl3ugnUaKUnzQswKqOG3M8/P1v1AB5NJwlHTuvTq1cs4mpeG2rCg==", + "requires": { + "rrule": "2.4.1" + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -14463,6 +14567,12 @@ "yallist": "^4.0.0" } }, + "luxon": { + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.1.tgz", + "integrity": "sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw==", + "optional": true + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -15382,9 +15492,9 @@ } }, "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==" }, "napi-build-utils": { "version": "1.0.2", @@ -15840,13 +15950,13 @@ "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==" }, "postcss": { - "version": "8.4.27", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", - "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "requires": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" } }, "postcss-import": { @@ -16310,6 +16420,14 @@ "glob": "^7.1.3" } }, + "rrule": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.4.1.tgz", + "integrity": "sha512-+NcvhETefswZq13T8nkuEnnQ6YgUeZaqMqVbp+ZiFDPCbp3AVgQIwUvNVDdMNrP05bKZG9ddDULFp0qZZYDrxg==", + "requires": { + "luxon": "^1.3.3" + } + }, "run-applescript": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", @@ -16623,9 +16741,9 @@ "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==" }, "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==" }, "source-map-support": { "version": "0.5.21", diff --git a/package.json b/package.json index d104452..ec5331b 100644 --- a/package.json +++ b/package.json @@ -20,15 +20,13 @@ "@stripe/stripe-js": "2.2.1", "@tailwindcss/forms": "0.5.7", "@tailwindcss/typography": "^0.5.4", - "@types/node": "20.4.7", - "@types/react": "18.2.18", - "@types/react-dom": "18.2.7", - "@types/webpack-env": "^1.18.1", "autoprefixer": "^10.4.12", "cheerio": "^1.0.0-rc.12", "clsx": "^1.2.1", + "dayjs": "^1.11.10", "fast-glob": "^3.2.11", "feed": "^4.2.2", + "ical": "^0.8.0", "next": "13.4.16", "next-themes": "^0.2.1", "postmark": "4.0.2", @@ -41,9 +39,14 @@ "typescript": "5.1.6" }, "devDependencies": { + "@types/ical": "^0.8.3", + "@types/node": "20.4.7", + "@types/react": "18.2.18", + "@types/react-dom": "18.2.7", + "@types/webpack-env": "^1.18.1", "eslint": "8.45.0", "eslint-config-next": "13.4.16", "prettier": "^3.0.1", "prettier-plugin-tailwindcss": "^0.5.2" } -} \ No newline at end of file +} diff --git a/src/app/calendar/calendar.tsx b/src/app/calendar/calendar.tsx new file mode 100644 index 0000000..9cc3dd7 --- /dev/null +++ b/src/app/calendar/calendar.tsx @@ -0,0 +1,241 @@ +'use client' + +import { + ChevronLeftIcon, + ChevronRightIcon, + ClockIcon, +} from '@heroicons/react/20/solid' + +import dayjs from "dayjs"; +import React from 'react'; +import { Calendar, Event } from './page'; +import Link from 'next/link'; + +interface day { + date: dayjs.Dayjs; + isCurrentMonth: boolean; + isToday: boolean; +} + + +function classNames(...classes: string[]): string { + return classes.filter(Boolean).join(' '); +} + +const getEvents = (cal: Calendar, d: dayjs.Dayjs): Event[] => { + const year = cal[d.year()]; + if (!year) { + return []; + } + + const month = year[d.month()]; + if (!month) { + return []; + } + + return month[d.date()] || []; +} + +export const CalendarComponent: React.FC<{ calendar: Calendar }> = ({ calendar }) => { + const [selectedDay, setSelectedDay] = React.useState(dayjs().startOf('day')); + const [selectedMonth, setSelectedMonth] = React.useState(dayjs().startOf('month')); + + const days = React.useMemo(() => { + // Number of greyed days shown before the beginning of the current month. + const renderedDaysBeforeMonth = selectedMonth.day(); + const firstDay = selectedMonth.subtract(renderedDaysBeforeMonth, 'day'); + const month = selectedMonth.month(); + const today = dayjs().startOf('day'); + + let current = firstDay; + const days: day[] = []; + + // Fill out the first week with days from the previous month. + for (let i = 0; i < renderedDaysBeforeMonth; i++) { + days.push({ + date: current, + isCurrentMonth: false, + isToday: current.isSame(today), + }); + current = current.add(1, 'day'); + } + + // Add the days for the selected month. + while (current.month() === month) { + days.push({ + date: current, + isCurrentMonth: true, + isToday: current.isSame(today), + }); + current = current.add(1, 'day'); + } + + // Finish out the week with days from the following month. + while (current.day() > 0) { + days.push({ + date: current, + isCurrentMonth: false, + isToday: current.isSame(today), + }); + current = current.add(1, 'day'); + } + + return days; + }, [selectedMonth]); + + const isSelectedDay = (d: day): boolean => { + return d.date.isSame(selectedDay); + } + + const selectedDayEvents = React.useMemo(() => { + return getEvents(calendar, selectedDay); + }, [calendar, selectedDay]); + + // TODO: Dark mode + + return ( +
{event.name}
+ +No events on this day
+ )} ++ If you are interested in reserving the hall, please see the + hall rental page + . +
++ Please check the + calendar + for availability. +