diff --git a/package-lock.json b/package-lock.json index 371ba9b..c727b04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,7 +65,7 @@ "@typescript-eslint/parser": "^6.18.0", "autoprefixer": "^10.4.14", "dotenv": "^16.1.4", - "drizzle-kit": "^0.20.10", + "drizzle-kit": "^0.20.13", "eslint": "^8.55.0", "eslint-config-next": "^14.0.3", "postcss": "^8.4.33", @@ -323,9 +323,9 @@ } }, "node_modules/@drizzle-team/studio": { - "version": "0.0.37", - "resolved": "https://registry.npmjs.org/@drizzle-team/studio/-/studio-0.0.37.tgz", - "integrity": "sha512-LZyAPGJBX43jsrVZh7+w1Jig/BC6PJx63ReHUYK+GRQYNY9UJNlPXmn1uC/LMRX+A7JwYM4Sr4Fg/hnJSqlfgA==", + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@drizzle-team/studio/-/studio-0.0.39.tgz", + "integrity": "sha512-c5Hkm7MmQC2n5qAsKShjQrHoqlfGslB8+qWzsGGZ+2dHMRTNG60UuzalF0h0rvBax5uzPXuGkYLGaQ+TUX3yMw==", "dev": true, "dependencies": { "superjson": "^2.2.1" @@ -4030,12 +4030,12 @@ } }, "node_modules/drizzle-kit": { - "version": "0.20.10", - "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.20.10.tgz", - "integrity": "sha512-GoBmfAWrZiX2ZHMGlVg7w34bnJw1gbQIzhGr1cROK6+0eikhFNSR4a4G8jtD3FO5JZKbbWHuNA5YFDJu6Us0Tw==", + "version": "0.20.13", + "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.20.13.tgz", + "integrity": "sha512-j9oZSQXNWG+KBJm0Sg3S/zJpncHGKnpqNfFuM4NUxUMGTcihDHhP9SW6Jncqwb5vsP1Xm0a8JLm3PZUIspC/oA==", "dev": true, "dependencies": { - "@drizzle-team/studio": "^0.0.37", + "@drizzle-team/studio": "^0.0.39", "@esbuild-kit/esm-loader": "^2.5.5", "camelcase": "^7.0.1", "chalk": "^5.2.0", diff --git a/package.json b/package.json index c6d7d06..1ebfb30 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "@typescript-eslint/parser": "^6.18.0", "autoprefixer": "^10.4.14", "dotenv": "^16.1.4", - "drizzle-kit": "^0.20.10", + "drizzle-kit": "^0.20.13", "eslint": "^8.55.0", "eslint-config-next": "^14.0.3", "postcss": "^8.4.33", diff --git a/src/components/index/form-old.tsx b/src/components/index/form-old.tsx deleted file mode 100644 index d400973..0000000 --- a/src/components/index/form-old.tsx +++ /dev/null @@ -1,211 +0,0 @@ -"use client"; - -import { useForm } from "@mantine/form"; -import { generate } from "random-words"; -import { useLocalstorageStore } from "fpp/store/local-storage.store"; -import React, { useEffect, useState } from "react"; -import { Autocomplete, Button, Group, TextInput } from "@mantine/core"; -import { IconArrowBadgeRightFilled } from "@tabler/icons-react"; -import { useRouter } from "next/router"; -import { type ClientLog } from "fpp/constants/error.constant"; -import { logMsg, roomEvent } from "fpp/constants/logging.constant"; -import { type Logger } from "next-axiom"; -import * as Sentry from "@sentry/nextjs"; - -const IndexForm = ({ logger }: { logger: Logger }) => { - const router = useRouter(); - - const [active, setActiveRooms] = useState([]); - const [random, setRandomRoom] = useState(""); - - useEffect(() => { - void fetch(`${process.env.NEXT_PUBLIC_API_ROOT}api/get-rooms`) - .then((res) => - res.json().then( - (data) => - data as { - activeRooms: string[]; - usedRooms: string[]; - }, - ), - ) - .catch((e) => { - Sentry.captureException(e); - if (e instanceof Error) { - logger.error(logMsg.GET_ROOMS_FAILED, { ...e }); - } - return { - activeRooms: [], - usedRooms: [], - }; - }) - .then((data) => { - const { activeRooms, usedRooms } = data as { - activeRooms: string[]; - usedRooms: string[]; - }; - setActiveRooms(activeRooms); - for (let i = 3; i <= 11; i++) { - const filtered = generate({ - minLength: 3, - maxLength: i, - exactly: 200, - }).filter((item) => !usedRooms?.includes(item)); - if (filtered.length > 0) { - setRandomRoom(filtered[0] ?? ""); - } - } - }); - }, []); - - const visitorId = useLocalstorageStore((state) => state.visitorId); - - const room = useLocalstorageStore((state) => state.room); - const setRoom = useLocalstorageStore((state) => state.setRoom); - const username = useLocalstorageStore((state) => state.username); - const setUsername = useLocalstorageStore((state) => state.setUsername); - - useEffect(() => { - if (!room || room === "null" || room === "undefined") { - setRoom(null); - } else { - router - .push(`/room/${room}`) - .then(() => ({})) - .catch(() => ({})); - } - }, [room]); - - const [recentRoom, setRecentRoom] = useState(null); - useEffect(() => { - const recentRoom = localStorage.getItem("recentRoom"); - if (recentRoom) { - setRecentRoom(recentRoom); - } - }, []); - - const form = useForm({ - initialValues: { - username: username ?? "", - room: random ?? generate({ minLength: 3, exactly: 1 })[0] ?? "", - }, - validate: { - username: (value) => - value.replace(/[^A-Za-z]/g, "").length < 3 || - value.replace(/[^A-Za-z]/g, "").length > 15, - room: (value) => - value.replace(/[^A-Za-z]/g, "").length < 3 || - value.replace(/[^A-Za-z]/g, "").length > 15, - }, - }); - - const [usernameInvalid, setUsernameInvalid] = useState(false); - - useEffect(() => { - setUsernameInvalid( - !form.values.username || - form.values.username.replace(/[^A-Za-z]/g, "").length < 3, - ); - }, [form.values.username]); - - return ( -
- -
{ - setUsername(form.values.username); - const roomName = form.values.room - .replace(/[^A-Za-z]/g, "") - .toLowerCase(); - - const logPayload: ClientLog = { - visitorId, - room: roomName, - }; - - if (active.includes(roomName)) { - logger.info(logMsg.TRACK_ROOM_EVENT, { - ...logPayload, - event: roomEvent.ENTER_EXISTING_ROOM, - }); - } else if (roomName === random) { - logger.info(logMsg.TRACK_ROOM_EVENT, { - ...logPayload, - event: roomEvent.ENTER_RANDOM_ROOM, - }); - } else { - logger.info(logMsg.TRACK_ROOM_EVENT, { - ...logPayload, - event: roomEvent.ENTER_NEW_ROOM, - }); - } - setRoom(roomName); - await router.push(`/room/${roomName}`); - })} - > -
-
- - - {/**/} - {/**/} - - 1 ? active : []} - /> - - -
-
-
-
- ); -}; - -export default IndexForm; diff --git a/src/components/index/form.tsx b/src/components/index/form.tsx index 7e54354..c9df6e9 100644 --- a/src/components/index/form.tsx +++ b/src/components/index/form.tsx @@ -6,19 +6,15 @@ import React, { useEffect } from "react"; import { Button, Group, TextInput } from "@mantine/core"; import { IconArrowBadgeRightFilled } from "@tabler/icons-react"; import { useRouter } from "next/router"; -import { type Logger } from "next-axiom"; -import { logMsg, roomEvent } from "fpp/constants/logging.constant"; import { api } from "fpp/utils/api"; +import { RoomEvent } from "fpp/server/db/schema"; -const IndexForm = ({ logger }: { logger: Logger }) => { +const IndexForm = () => { const router = useRouter(); - const userId = useLocalstorageStore((state) => state.userId); - const roomReadable = useLocalstorageStore((state) => state.roomReadable); - const setRoomReadable = useLocalstorageStore( - (state) => state.setRoomReadable, - ); + const setRoomReadable = useLocalstorageStore((state) => state.setRoomName); + const setRoomEvent = useLocalstorageStore((state) => state.setRoomEvent); const { data: randomRoomNumber } = api.room.getOpenRoomNumber.useQuery(); @@ -48,7 +44,9 @@ const IndexForm = ({ logger }: { logger: Logger }) => { }, }); + // let secondRender = false; useEffect(() => { + // secondRender = true; const roomValue = form.values.room .replace(/[^A-Za-z0-9]/g, "") .toUpperCase(); @@ -69,11 +67,7 @@ const IndexForm = ({ logger }: { logger: Logger }) => { console.error("No random room number found"); } setRoomReadable(String(randomRoomNumber)); - logger.info(logMsg.TRACK_ROOM_EVENT, { - userId, - roomNumber: String(randomRoomNumber), - event: roomEvent.ENTER_RANDOM_ROOM, - }); + setRoomEvent(RoomEvent.ENTERED_RANDOM_ROOM); router .push(`/room/${randomRoomNumber}`) .then(() => ({})) @@ -87,11 +81,7 @@ const IndexForm = ({ logger }: { logger: Logger }) => { onSubmit={form.onSubmit(() => { const roomValue = form.values.room.toLowerCase(); setRoomReadable(roomValue); - logger.info(logMsg.TRACK_ROOM_EVENT, { - userId, - room: roomValue, - event: roomEvent.ENTER_NEW_ROOM, - }); + setRoomEvent(RoomEvent.ENTERED_ROOM_DIRECTLY); router .push(`/room/${roomValue}`) .then(() => ({})) diff --git a/src/components/index/scroll-buttons.tsx b/src/components/index/scroll-buttons.tsx deleted file mode 100644 index 210d5c9..0000000 --- a/src/components/index/scroll-buttons.tsx +++ /dev/null @@ -1,88 +0,0 @@ -"use client"; - -import { Button } from "@mantine/core"; -import { - IconArrowBadgeDownFilled, - IconArrowBadgeUpFilled, -} from "@tabler/icons-react"; -import React from "react"; -import { AnimatePresence, motion } from "framer-motion"; -import Link from "next/link"; - -const ScrollButtons = ({ inView }: { inView: boolean }) => { - return ( - <> - - {inView ? ( - - { - window.scrollTo({ top: 0, left: 0, behavior: "smooth" }); - }} - > - - - - ) : ( - - - - - - )} - - - ); -}; - -export default ScrollButtons; diff --git a/src/components/layout/footer.tsx b/src/components/layout/footer.tsx index 9c1b998..4b6bd1f 100644 --- a/src/components/layout/footer.tsx +++ b/src/components/layout/footer.tsx @@ -1,10 +1,6 @@ import Link from "next/link"; const links = [ - { - url: "/imprint", - title: "Imprint & Privacy Policy", - }, { url: "/analytics", title: "Analytics", @@ -13,6 +9,10 @@ const links = [ url: "/contact", title: "Contact", }, + { + url: "/imprint", + title: "Imprint & Privacy Policy", + }, ]; export function Footer() { @@ -38,6 +38,15 @@ export function Footer() {
+ {links.map((link) => ( + + {link.title} + + ))} GitHub - {links.map((link) => ( - - {link.title} - - ))}
diff --git a/src/components/layout/hero.tsx b/src/components/layout/hero.tsx index 5dd8aa8..6d00625 100644 --- a/src/components/layout/hero.tsx +++ b/src/components/layout/hero.tsx @@ -2,7 +2,7 @@ import { Button, Container, Text } from "@mantine/core"; import Link from "next/link"; import { useRouter } from "next/router"; -export function Hero(props: { withDescription?: true; full?: true }) { +export function Hero(props: { full?: true }) { const router = useRouter(); // which page are we on @@ -88,20 +88,6 @@ export function Hero(props: { withDescription?: true; full?: true }) { )} - {props.withDescription && ( - -

- Say goodbye to complicated and expensive planning poker tools with - this -
- user-friendly app. Based on the Fibonacci sequence for story point - estimation, -
- this tool is suitable for any agile project management needs, - whether you use Scrum, Kanban, or your own custom Jira workflow. -

-
- )} ); diff --git a/src/components/room/interactions.tsx b/src/components/room/interactions.tsx index d9c3eed..5ff01ec 100644 --- a/src/components/room/interactions.tsx +++ b/src/components/room/interactions.tsx @@ -4,30 +4,29 @@ import { useRef } from "react"; import { useRouter } from "next/router"; import { fibonacciSequence } from "fpp/constants/fibonacci.constant"; import { type Logger } from "next-axiom"; -import { logMsg, roomEvent } from "fpp/constants/logging.constant"; -import { RouteType } from "fpp/server/db/schema"; import { useRoomStateStore } from "fpp/store/room-state.store"; import { useLocalstorageStore } from "fpp/store/local-storage.store"; import { api } from "fpp/utils/api"; import { roomStateStatus } from "fpp/server/room-state/room-state.entity"; +import { sendTrackEvent } from "fpp/utils/send-track-event.util"; +import { EventType } from "fpp/server/db/schema"; +import { isValidMediumint } from "fpp/utils/number.utils"; export const Interactions = ({ roomId, - roomReadable, + roomName, userId, logger, }: { roomId: number; - roomReadable: string; + roomName: string; userId: string; logger: Logger; }) => { const router = useRouter(); const setRoomId = useLocalstorageStore((store) => store.setRoomId); - const setRoomReadable = useLocalstorageStore( - (store) => store.setRoomReadable, - ); + const setRoomReadable = useLocalstorageStore((store) => store.setRoomName); // User state const estimation = useRoomStateStore((store) => store.estimation); @@ -82,13 +81,16 @@ export const Interactions = ({ title: "Room url copied to clipboard", message: "Share it with your team!", }); + sendTrackEvent({ + event: EventType.COPIED_ROOM_LINK, + userId, + logger, + }); }} > - {/^\d+$/.test(roomReadable) && - roomReadable.length === 6 && - Number.isInteger(roomReadable) - ? roomReadable.slice(0, 3) + " " + roomReadable.slice(3) - : roomReadable.toUpperCase()} + {isValidMediumint(roomName) && roomName.length === 6 + ? roomName.slice(0, 3) + " " + roomName.slice(3) + : roomName.toUpperCase()}
@@ -109,12 +111,6 @@ export const Interactions = ({