diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..ff573fe2 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,25 @@ +name: Lint + +on: + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '21' + cache: 'npm' + - name: Install dependencies + run: | + npm install + - name: Lint + run: npm run lint diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 2988eba4..aff68029 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -1,4 +1,4 @@ -name: Deploy to GitHub Pages +name: GitHub Pages on: push: @@ -24,7 +24,6 @@ jobs: - name: Install dependencies run: | npm install - npm install @rollup/rollup-linux-x64-gnu - name: Build run: npm run build - name: Setup Pages @@ -35,6 +34,7 @@ jobs: path: './dist' deploy: + if: github.ref == 'refs/heads/main' needs: build # Grant GITHUB_TOKEN the permissions required to make a Pages deployment permissions: diff --git a/package-lock.json b/package-lock.json index e14f1c1b..c025b96f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "auction-website-vite", + "name": "auction-website", "version": "3.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "auction-website-vite", + "name": "auction-website", "version": "3.0.0", "dependencies": { "bootstrap": "^5.3.2", @@ -13,7 +13,8 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-icons": "^4.12.0", - "react-router-dom": "^6.21.0" + "react-router-dom": "^6.21.0", + "rollup": "^4.12.1" }, "devDependencies": { "@types/react": "^18.2.43", @@ -871,19 +872,162 @@ "node": ">=14.0.0" } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.1.tgz", + "integrity": "sha512-iU2Sya8hNn1LhsYyf0N+L4Gf9Qc+9eBTJJJsaOGUp+7x4n2M9dxTt8UvhJl3oeftSjblSlpCfvjA/IfP3g5VjQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.1.tgz", + "integrity": "sha512-wlzcWiH2Ir7rdMELxFE5vuM7D6TsOcJ2Yw0c3vaBR3VOsJFVTx9xvwnAvhgU5Ii8Gd6+I11qNHwndDscIm0HXg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ] + }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.1.tgz", - "integrity": "sha512-LtYcLNM+bhsaKAIGwVkh5IOWhaZhjTfNOkGzGqdHvhiCUVuJDalvDxEdSnhFzAn+g23wgsycmZk1vbnaibZwwA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.1.tgz", + "integrity": "sha512-YRXa1+aZIFN5BaImK+84B3uNK8C6+ynKLPgvn29X9s0LTVCByp54TB7tdSMHDR7GTV39bz1lOmlLDuedgTwwHg==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "darwin" ] }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.1.tgz", + "integrity": "sha512-opjWJ4MevxeA8FhlngQWPBOvVWYNPFkq6/25rGgG+KOy0r8clYwL1CFd+PGwRqqMFVQ4/Qd3sQu5t7ucP7C/Uw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.1.tgz", + "integrity": "sha512-uBkwaI+gBUlIe+EfbNnY5xNyXuhZbDSx2nzzW8tRMjUmpScd6lCQYKY2V9BATHtv5Ef2OBq6SChEP8h+/cxifQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.1.tgz", + "integrity": "sha512-0bK9aG1kIg0Su7OcFTlexkVeNZ5IzEsnz1ept87a0TUgZ6HplSgkJAnFpEVRW7GRcikT4GlPV0pbtVedOaXHQQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.1.tgz", + "integrity": "sha512-qB6AFRXuP8bdkBI4D7UPUbE7OQf7u5OL+R94JE42Z2Qjmyj74FtDdLGeriRyBDhm4rQSvqAGCGC01b8Fu2LthQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.1.tgz", + "integrity": "sha512-sHig3LaGlpNgDj5o8uPEoGs98RII8HpNIqFtAI8/pYABO8i0nb1QzT0JDoXF/pxzqO+FkxvwkHZo9k0NJYDedg==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.1.tgz", + "integrity": "sha512-nD3YcUv6jBJbBNFvSbp0IV66+ba/1teuBcu+fBBPZ33sidxitc6ErhON3JNavaH8HlswhWMC3s5rgZpM4MtPqQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.12.1.tgz", + "integrity": "sha512-7/XVZqgBby2qp/cO0TQ8uJK+9xnSdJ9ct6gSDdEr4MfABrjTyrW6Bau7HQ73a2a5tPB7hno49A0y1jhWGDN9OQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.1.tgz", + "integrity": "sha512-CYc64bnICG42UPL7TrhIwsJW4QcKkIt9gGlj21gq3VV0LL6XNb1yAdHVp1pIi9gkts9gGcT3OfUYHjGP7ETAiw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.1.tgz", + "integrity": "sha512-LN+vnlZ9g0qlHGlS920GR4zFCqAwbv2lULrR29yGaWP9u7wF5L7GqWu9Ah6/kFZPXPUkpdZwd//TNR+9XC9hvA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.1.tgz", + "integrity": "sha512-n+vkrSyphvmU0qkQ6QBNXCGr2mKjhP08mPRM/Xp5Ck2FV4NrHU+y6axzDeixUrCBHVUS51TZhjqrKBBsHLKb2Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@swc/core": { "version": "1.3.101", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.101.tgz", @@ -1094,6 +1238,11 @@ "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==", "dev": true }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + }, "node_modules/@types/node": { "version": "20.10.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", @@ -2115,7 +2264,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -3373,6 +3521,37 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rollup": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.12.1.tgz", + "integrity": "sha512-ggqQKvx/PsB0FaWXhIvVkSWh7a/PCLQAsMjBc+nA2M8Rv2/HG0X6zvixAB7KyZBRtifBUhy5k8voQX/mRnABPg==", + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.12.1", + "@rollup/rollup-android-arm64": "4.12.1", + "@rollup/rollup-darwin-arm64": "4.12.1", + "@rollup/rollup-darwin-x64": "4.12.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.12.1", + "@rollup/rollup-linux-arm64-gnu": "4.12.1", + "@rollup/rollup-linux-arm64-musl": "4.12.1", + "@rollup/rollup-linux-riscv64-gnu": "4.12.1", + "@rollup/rollup-linux-x64-gnu": "4.12.1", + "@rollup/rollup-linux-x64-musl": "4.12.1", + "@rollup/rollup-win32-arm64-msvc": "4.12.1", + "@rollup/rollup-win32-ia32-msvc": "4.12.1", + "@rollup/rollup-win32-x64-msvc": "4.12.1", + "fsevents": "~2.3.2" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -3887,35 +4066,6 @@ } } }, - "node_modules/vite/node_modules/rollup": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.1.tgz", - "integrity": "sha512-pgPO9DWzLoW/vIhlSoDByCzcpX92bKEorbgXuZrqxByte3JFk2xSW2JEeAcyLc9Ru9pqcNNW+Ob7ntsk2oT/Xw==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.9.1", - "@rollup/rollup-android-arm64": "4.9.1", - "@rollup/rollup-darwin-arm64": "4.9.1", - "@rollup/rollup-darwin-x64": "4.9.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.9.1", - "@rollup/rollup-linux-arm64-gnu": "4.9.1", - "@rollup/rollup-linux-arm64-musl": "4.9.1", - "@rollup/rollup-linux-riscv64-gnu": "4.9.1", - "@rollup/rollup-linux-x64-gnu": "4.9.1", - "@rollup/rollup-linux-x64-musl": "4.9.1", - "@rollup/rollup-win32-arm64-msvc": "4.9.1", - "@rollup/rollup-win32-ia32-msvc": "4.9.1", - "@rollup/rollup-win32-x64-msvc": "4.9.1", - "fsevents": "~2.3.2" - } - }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", diff --git a/package.json b/package.json index 3b9e7e83..dfacd642 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-icons": "^4.12.0", - "react-router-dom": "^6.21.0" + "react-router-dom": "^6.21.0", + "rollup": "^4.12.1" }, "devDependencies": { "@types/react": "^18.2.43", diff --git a/src/App.jsx b/src/App.jsx index 457e4313..45ece017 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,3 +1,4 @@ +import PropTypes from "prop-types"; import "./App.css"; import { BrowserRouter as Router, @@ -6,7 +7,7 @@ import { Navigate, } from "react-router-dom"; import "bootstrap/dist/css/bootstrap.min.css"; -import { AutoSignIn } from "./utils/firebaseUtils"; +import { AutoSignIn } from "./firebase/AutoSignIn"; import { ItemsProvider } from "./contexts/ItemsProvider"; import { ModalsProvider } from "./contexts/ModalsProvider"; import Navbar from "./components/Navbar"; @@ -55,4 +56,9 @@ function App() { ); } +App.propTypes = { + children: PropTypes.arrayOf(PropTypes.element), + condition: PropTypes.bool +} + export default App; diff --git a/src/components/Footer.jsx b/src/components/Footer.jsx index 18bf8c72..cef6f6a5 100644 --- a/src/components/Footer.jsx +++ b/src/components/Footer.jsx @@ -1,4 +1,3 @@ -import React from "react"; import { FaGithub } from "react-icons/fa"; const Footer = () => { diff --git a/src/components/Grid.jsx b/src/components/Grid.jsx index dd6dc5e4..36e016a0 100644 --- a/src/components/Grid.jsx +++ b/src/components/Grid.jsx @@ -1,4 +1,4 @@ -import React, { useContext } from "react"; +import { useContext } from "react"; import { Item } from "./Item"; import { ItemsContext } from "../contexts/ItemsProvider"; diff --git a/src/components/Item.jsx b/src/components/Item.jsx index 92e0e0e4..efc80987 100644 --- a/src/components/Item.jsx +++ b/src/components/Item.jsx @@ -1,15 +1,11 @@ -import React, { useState, useEffect, useContext } from "react"; +import { useState, useEffect, useContext } from "react"; +import PropTypes from "prop-types"; +import { itemStatus } from "../utils/itemStatus"; import { formatTime, formatMoney } from "../utils/formatString"; -import { ModalsContext, ModalTypes } from "../contexts/ModalsProvider"; +import { ModalsContext } from "../contexts/ModalsProvider"; +import { ModalTypes } from "../utils/modalTypes"; -const itemStatus = (item) => { - const bids = Object.keys(item.bids ?? {}).length; - const amount = bids ? item.bids[bids].amount : item.startingPrice ?? 0; - const winner = bids ? item.bids[bids].uid : ""; - return { bids, amount, winner }; -}; - -const Item = ({ item }) => { +export const Item = ({ item }) => { const { openModal } = useContext(ModalsContext); const [primaryImageSrc, setPrimaryImageSrc] = useState(""); @@ -97,4 +93,13 @@ const Item = ({ item }) => { ); }; -export { Item, itemStatus }; +Item.propTypes = { + item: PropTypes.shape({ + startingPrice: PropTypes.number.isRequired, + currency: PropTypes.string.isRequired, + endTime: PropTypes.object.isRequired, + primaryImage: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + subtitle: PropTypes.string.isRequired, + }) +} diff --git a/src/components/Modal.jsx b/src/components/Modal.jsx index 6c1765e4..8632e3f9 100644 --- a/src/components/Modal.jsx +++ b/src/components/Modal.jsx @@ -1,11 +1,13 @@ -import React, { useState, useEffect, useContext } from "react"; +import { useState, useEffect, useContext } from "react"; +import PropTypes from "prop-types"; import ReactDOM from "react-dom"; -import { itemStatus } from "./Item"; +import { itemStatus } from "../utils/itemStatus"; import { formatField, formatMoney } from "../utils/formatString"; import { updateProfile } from "firebase/auth"; import { doc, setDoc, updateDoc } from "firebase/firestore"; -import { auth, db } from "../utils/firebaseConfig"; -import { ModalsContext, ModalTypes } from "../contexts/ModalsProvider"; +import { auth, db } from "../firebase/config"; +import { ModalsContext } from "../contexts/ModalsProvider"; +import { ModalTypes } from "../utils/modalTypes"; const Modal = ({ type, title, children }) => { const { closeModal, currentModal } = useContext(ModalsContext); @@ -39,6 +41,12 @@ const Modal = ({ type, title, children }) => { ); }; +Modal.propTypes = { + type: PropTypes.string, + title: PropTypes.string, + children: PropTypes.arrayOf(PropTypes.element) +} + const InfoModal = () => { const { openModal, closeModal, activeItem } = useContext(ModalsContext); const [secondaryImageSrc, setSecondaryImageSrc] = useState(""); @@ -107,7 +115,7 @@ const SignUpModal = () => { We use anonymous authentication provided by Google. Your account is attached to your device signature.

-

The username just lets us know who's bidding!

+

The username just lets us know who's bidding!

e.preventDefault()}>
{ You are about to place a bid on {activeItem.title}

- (This is just a demo, you're not bidding real money) + (This is just a demo, you're not bidding real money)

e.preventDefault()}>
diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx index d4ef0781..8eb7cd3c 100644 --- a/src/components/Navbar.jsx +++ b/src/components/Navbar.jsx @@ -1,8 +1,10 @@ -import React, { useState, useEffect, useContext } from "react"; +import { useState, useEffect, useContext } from "react"; +import PropTypes from "prop-types"; import { useNavigate } from "react-router"; -import { auth } from "../utils/firebaseConfig"; +import { auth } from "../firebase/config"; import { onAuthStateChanged } from "firebase/auth"; -import { ModalsContext, ModalTypes } from "../contexts/ModalsProvider"; +import { ModalsContext } from "../contexts/ModalsProvider"; +import { ModalTypes } from "../utils/modalTypes"; const Navbar = ({ admin }) => { const openModal = useContext(ModalsContext).openModal; @@ -64,4 +66,8 @@ const Navbar = ({ admin }) => { ); }; +Navbar.propTypes = { + admin: PropTypes.bool +} + export default Navbar; diff --git a/src/components/Row.jsx b/src/components/Row.jsx index 705957ed..e0fe1a12 100644 --- a/src/components/Row.jsx +++ b/src/components/Row.jsx @@ -1,11 +1,12 @@ -import React, { useState, useEffect } from "react"; +import { useState, useEffect } from "react"; +import PropTypes from "prop-types"; import { formatTime, formatMoney } from "../utils/formatString"; -import { itemStatus } from "./Item"; +import { itemStatus } from "../utils/itemStatus"; import { getDoc, doc } from "firebase/firestore"; -import { db } from "../utils/firebaseConfig"; -import { editItems } from "../utils/firebaseUtils"; +import { db } from "../firebase/config"; +import { editItems } from "../firebase/utils"; -const Row = ({ item }) => { +export const Row = ({ item }) => { const [amount, setAmount] = useState(item.startingPrice); const [bids, setBids] = useState(0); const [winner, setWinner] = useState(""); @@ -72,4 +73,12 @@ const Row = ({ item }) => { ); }; -export default Row; +Row.propTypes = { + item: PropTypes.shape({ + startingPrice: PropTypes.number.isRequired, + currency: PropTypes.string.isRequired, + endTime: PropTypes.object.isRequired, + id: PropTypes.number.isRequired, + title: PropTypes.string.isRequired, + }) +} diff --git a/src/components/Table.jsx b/src/components/Table.jsx new file mode 100644 index 00000000..c804273a --- /dev/null +++ b/src/components/Table.jsx @@ -0,0 +1,31 @@ +import { useContext } from "react"; +import { Row } from "./Row"; +import { ItemsContext } from "../contexts/ItemsProvider"; + +const Table = () => { + const { items } = useContext(ItemsContext); + + return ( + + + + + + + + + + + + + + {items.map((item) => ( + + ))} + +
IDTitlePriceBidsWinningTime LeftActions
+ ); +}; + +export default Table; + diff --git a/src/contexts/ItemsProvider.jsx b/src/contexts/ItemsProvider.jsx index 38dbca3f..6f03a862 100644 --- a/src/contexts/ItemsProvider.jsx +++ b/src/contexts/ItemsProvider.jsx @@ -1,7 +1,8 @@ -import React, { useEffect, useState, createContext } from "react"; -import { db } from "../utils/firebaseConfig"; +import { useEffect, useState, createContext } from "react"; +import PropTypes from "prop-types"; +import { db } from "../firebase/config"; import { onSnapshot, doc, setDoc } from "firebase/firestore"; -import { unflattenItems } from "../utils/firebaseUtils"; +import { unflattenItems } from "../firebase/utils"; export const ItemsContext = createContext(); @@ -29,3 +30,8 @@ export const ItemsProvider = ({ demo, children }) => { {children} ); }; + +ItemsProvider.propTypes = { + demo: PropTypes.bool, + children: PropTypes.arrayOf(PropTypes.element) +} diff --git a/src/contexts/ModalsProvider.jsx b/src/contexts/ModalsProvider.jsx index 26f63e11..460a808a 100644 --- a/src/contexts/ModalsProvider.jsx +++ b/src/contexts/ModalsProvider.jsx @@ -1,14 +1,9 @@ -import React, { createContext, useState } from "react"; +import { createContext, useState } from "react"; +import PropTypes from "prop-types"; +import { ModalTypes } from "../utils/modalTypes"; export const ModalsContext = createContext(); -export const ModalTypes = { - INFO: "info", - SIGN_UP: "signUp", - BID: "bid", - NONE: null, -}; - export const ModalsProvider = ({ children }) => { const [activeItem, setActiveItem] = useState({}); const [currentModal, setCurrentModal] = useState(ModalTypes.NONE); @@ -31,3 +26,7 @@ export const ModalsProvider = ({ children }) => { ); }; + +ModalsProvider.propTypes = { + children: PropTypes.arrayOf(PropTypes.element) +} diff --git a/src/firebase/AutoSignIn.jsx b/src/firebase/AutoSignIn.jsx new file mode 100644 index 00000000..7a2f2199 --- /dev/null +++ b/src/firebase/AutoSignIn.jsx @@ -0,0 +1,34 @@ +import { useEffect, useState } from "react"; +import { onAuthStateChanged, signInAnonymously } from "firebase/auth"; +import { getDoc, doc } from "firebase/firestore"; +import { auth, db } from "./config"; + +export const AutoSignIn = () => { + const [user, setUser] = useState(null); + const [admin, setAdmin] = useState(false); + + useEffect(() => { + const unsubscribe = onAuthStateChanged(auth, (user) => { + if (user && user.displayName) { + console.debug(`Signed-in: name=${user.displayName}, uid=${user.uid}`); + setUser(user); + + // Check if user is admin + const userDocRef = doc(db, "users", user.uid); + getDoc(userDocRef).then((docSnap) => { + if (docSnap.exists() && docSnap.data().admin) { + console.debug("User is admin"); + setAdmin(true); + } + }); + } else { + signInAnonymously(auth); + } + }); + + // Clean up the onAuthStateChanged listener when the component unmounts + return () => unsubscribe(); + }, []); + + return { user, admin }; +}; diff --git a/src/utils/firebaseConfig.jsx b/src/firebase/config.jsx similarity index 100% rename from src/utils/firebaseConfig.jsx rename to src/firebase/config.jsx diff --git a/src/utils/firebaseUtils.jsx b/src/firebase/utils.jsx similarity index 61% rename from src/utils/firebaseUtils.jsx rename to src/firebase/utils.jsx index f8b5a1ae..5d58b7f3 100644 --- a/src/utils/firebaseUtils.jsx +++ b/src/firebase/utils.jsx @@ -1,5 +1,3 @@ -import { useEffect, useState } from "react"; -import { onAuthStateChanged, signInAnonymously } from "firebase/auth"; import { getDoc, updateDoc, @@ -7,49 +5,19 @@ import { Timestamp, deleteField, } from "firebase/firestore"; -import { auth, db } from "./firebaseConfig"; +import { db } from "./config"; import yaml from "js-yaml"; -import { formatField } from "./formatString"; - -const AutoSignIn = () => { - const [user, setUser] = useState(null); - const [admin, setAdmin] = useState(false); - - useEffect(() => { - const unsubscribe = onAuthStateChanged(auth, (user) => { - if (user && user.displayName) { - console.debug(`Signed-in: name=${user.displayName}, uid=${user.uid}`); - setUser(user); - - // Check if user is admin - const userDocRef = doc(db, "users", user.uid); - getDoc(userDocRef).then((docSnap) => { - if (docSnap.exists() && docSnap.data().admin) { - console.debug("User is admin"); - setAdmin(true); - } - }); - } else { - signInAnonymously(auth); - } - }); - - // Clean up the onAuthStateChanged listener when the component unmounts - return () => unsubscribe(); - }, []); - - return { user, admin }; -}; +import { formatField } from "../utils/formatString"; const parseField = (key) => { - const match = key.match(/item(\d+)_bid(\d+)/); - return { - item: Number(match[1]), - bid: Number(match[2]), + const match = key.match(/item(\d+)_bid(\d+)/); + return { + item: Number(match[1]), + bid: Number(match[2]), + }; }; -}; - -const unflattenItems = (doc, demo) => { + +export const unflattenItems = (doc, demo) => { let items = {}; for (const [key, value] of Object.entries(doc.data())) { const { item, bid } = parseField(key); @@ -76,14 +44,14 @@ const unflattenItems = (doc, demo) => { } return Object.values(items); }; - -const editItems = (id = undefined, update = false, reset = false) => { + +export const editItems = (id = undefined, update = false, reset = false) => { fetch(import.meta.env.BASE_URL + "items.yml") .then((response) => response.text()) .then((text) => yaml.load(text)) .then((items) => { // If ID was provided, place that item in an array by itself - if (id) items = [items.find((item) => item.id === id)]; + if (id !== undefined) items = [items.find((item) => item.id === id)]; const docRef = doc(db, "auction", "items"); getDoc(docRef) @@ -114,5 +82,4 @@ const editItems = (id = undefined, update = false, reset = false) => { }); }); }; - -export { AutoSignIn, parseField, unflattenItems, editItems }; + \ No newline at end of file diff --git a/src/pages/Admin.jsx b/src/pages/Admin.jsx index 1d02fba9..3b0e45cd 100644 --- a/src/pages/Admin.jsx +++ b/src/pages/Admin.jsx @@ -1,11 +1,7 @@ -import React, { useContext } from "react"; -import { ItemsContext } from "../contexts/ItemsProvider"; -import Row from "../components/Row"; -import { editItems } from "../utils/firebaseUtils"; +import { editItems } from "../firebase/utils"; +import Table from "../components/Table"; function AdminPage() { - const { items } = useContext(ItemsContext); - return (
@@ -28,24 +24,7 @@ function AdminPage() { Update & Reset All
- - - - - - - - - - - - - - {items.map((item) => ( - - ))} - -
IDTitlePriceBidsWinningTime LeftActions
+ ); } diff --git a/src/utils/formatString.jsx b/src/utils/formatString.js similarity index 100% rename from src/utils/formatString.jsx rename to src/utils/formatString.js diff --git a/src/utils/itemStatus.js b/src/utils/itemStatus.js new file mode 100644 index 00000000..d92a6b5e --- /dev/null +++ b/src/utils/itemStatus.js @@ -0,0 +1,6 @@ +export const itemStatus = (item) => { + const bids = Object.keys(item.bids ?? {}).length; + const amount = bids ? item.bids[bids].amount : item.startingPrice ?? 0; + const winner = bids ? item.bids[bids].uid : ""; + return { bids, amount, winner }; +}; diff --git a/src/utils/modalTypes.js b/src/utils/modalTypes.js new file mode 100644 index 00000000..a4e00727 --- /dev/null +++ b/src/utils/modalTypes.js @@ -0,0 +1,6 @@ +export const ModalTypes = { + INFO: "info", + SIGN_UP: "signUp", + BID: "bid", + NONE: null, +};