Migrated to latest solid-start version
This commit is contained in:
parent
777b807225
commit
6fb057a102
42 changed files with 4727 additions and 2128 deletions
|
@ -1,14 +0,0 @@
|
|||
module.exports = {
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
project: ["./tsconfig.eslint.json", "./tsconfig.json"],
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
plugins: ["@typescript-eslint", "solid"],
|
||||
extends: [
|
||||
"plugin:solid/typescript",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier",
|
||||
],
|
||||
ignorePatterns: ["dist/**"],
|
||||
}
|
11
leaky-ships/.eslintrc.json
Normal file
11
leaky-ships/.eslintrc.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"plugins": ["solid"],
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:solid/typescript"
|
||||
]
|
||||
}
|
59
leaky-ships/.gitignore
vendored
59
leaky-ships/.gitignore
vendored
|
@ -1,44 +1,35 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# logs
|
||||
/log
|
||||
src/drizzle/migrations
|
||||
|
||||
# drizzle
|
||||
/drizzle/migrations
|
||||
dist
|
||||
.vinxi
|
||||
.output
|
||||
.vercel
|
||||
.netlify
|
||||
netlify
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# SolidJS
|
||||
/.solid/
|
||||
/dist/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# local env files
|
||||
# Environment
|
||||
.env
|
||||
.env*.local
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
*.launch
|
||||
.settings/
|
||||
|
||||
# Temp
|
||||
gitignore
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# playwright
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/playwright/.cache/
|
||||
/playwright/.cache/
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"name": "leaky-ships",
|
||||
"scripts": {
|
||||
"dev": "solid-start dev --port 3000",
|
||||
"start": "solid-start start --port 3000",
|
||||
"build": "solid-start build",
|
||||
"dev": "vinxi dev",
|
||||
"build": "vinxi build",
|
||||
"start": "vinxi start",
|
||||
"lint": "eslint --fix \"**/*.{ts,tsx,js,jsx}\"",
|
||||
"push": "drizzle-kit push:pg",
|
||||
"test": "pnpm playwright test --ui",
|
||||
|
@ -11,64 +11,65 @@
|
|||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@auth/core": "^0.13.0",
|
||||
"@auth/drizzle-adapter": "^0.3.2",
|
||||
"@auth/solid-start": "^0.1.1",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.4.2",
|
||||
"@fortawesome/pro-duotone-svg-icons": "^6.4.2",
|
||||
"@fortawesome/pro-light-svg-icons": "^6.4.2",
|
||||
"@fortawesome/pro-regular-svg-icons": "^6.4.2",
|
||||
"@fortawesome/pro-solid-svg-icons": "^6.4.2",
|
||||
"@fortawesome/pro-thin-svg-icons": "^6.4.2",
|
||||
"@fortawesome/sharp-solid-svg-icons": "^6.4.2",
|
||||
"@auth/core": "^0.27.0",
|
||||
"@auth/drizzle-adapter": "^0.7.0",
|
||||
"@auth/solid-start": "^0.6.1",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.5.1",
|
||||
"@fortawesome/pro-duotone-svg-icons": "^6.5.1",
|
||||
"@fortawesome/pro-light-svg-icons": "^6.5.1",
|
||||
"@fortawesome/pro-regular-svg-icons": "^6.5.1",
|
||||
"@fortawesome/pro-solid-svg-icons": "^6.5.1",
|
||||
"@fortawesome/pro-thin-svg-icons": "^6.5.1",
|
||||
"@fortawesome/sharp-solid-svg-icons": "^6.5.1",
|
||||
"@paralleldrive/cuid2": "^2.2.2",
|
||||
"@solidjs/meta": "^0.28.6",
|
||||
"@solidjs/router": "^0.8.3",
|
||||
"classnames": "^2.3.2",
|
||||
"@solidjs/meta": "^0.29.3",
|
||||
"@solidjs/router": "^0.12.4",
|
||||
"@solidjs/start": "^0.5.9",
|
||||
"classnames": "^2.5.1",
|
||||
"colors": "^1.4.0",
|
||||
"drizzle-orm": "^0.28.6",
|
||||
"drizzle-orm": "^0.29.4",
|
||||
"drizzle-zod": "^0.5.1",
|
||||
"http-status": "^1.7.0",
|
||||
"json-stable-stringify": "^1.0.2",
|
||||
"http-status": "^1.7.3",
|
||||
"json-stable-stringify": "^1.1.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"nodemailer": "^6.9.5",
|
||||
"nodemailer": "^6.9.10",
|
||||
"object-hash": "^3.0.0",
|
||||
"postgres": "^3.3.5",
|
||||
"socket.io": "^4.7.2",
|
||||
"socket.io-client": "^4.7.2",
|
||||
"postgres": "^3.4.3",
|
||||
"socket.io": "^4.7.4",
|
||||
"socket.io-client": "^4.7.4",
|
||||
"solid-color": "^0.0.4",
|
||||
"solid-js": "^1.7.11",
|
||||
"solid-start": "^0.3.5",
|
||||
"solid-js": "^1.8.15",
|
||||
"tinycolor2": "^1.6.0",
|
||||
"unique-names-generator": "^4.7.1",
|
||||
"zod": "3.21.1"
|
||||
"vinxi": "^0.3.3",
|
||||
"zod": "3.22.4"
|
||||
},
|
||||
"packageManager": "pnpm@8.7.4",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.37.1",
|
||||
"@total-typescript/ts-reset": "^0.4.2",
|
||||
"@types/json-stable-stringify": "^1.0.34",
|
||||
"@types/node": "^20.5.9",
|
||||
"@types/nodemailer": "^6.4.9",
|
||||
"@types/object-hash": "^3.0.4",
|
||||
"@types/web-bluetooth": "^0.0.17",
|
||||
"@typescript-eslint/eslint-plugin": "^6.6.0",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"dotenv": "^16.3.1",
|
||||
"drizzle-kit": "^0.19.13",
|
||||
"eslint": "^8.48.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-solid": "^0.12.1",
|
||||
"@playwright/test": "^1.41.2",
|
||||
"@total-typescript/ts-reset": "^0.5.1",
|
||||
"@types/json-stable-stringify": "^1.0.36",
|
||||
"@types/node": "^20.11.19",
|
||||
"@types/nodemailer": "^6.4.14",
|
||||
"@types/object-hash": "^3.0.6",
|
||||
"@types/web-bluetooth": "^0.0.20",
|
||||
"@typescript-eslint/eslint-plugin": "^7.0.2",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"dotenv": "^16.4.5",
|
||||
"drizzle-kit": "^0.20.14",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-solid": "^0.13.1",
|
||||
"pg": "^8.11.3",
|
||||
"postcss": "^8.4.29",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier-plugin-organize-imports": "^3.2.3",
|
||||
"prettier-plugin-tailwindcss": "^0.5.4",
|
||||
"sass": "^1.66.1",
|
||||
"solid-start-node": "^0.3.5",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^4.4.9"
|
||||
"postcss": "^8.4.35",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-organize-imports": "^3.2.4",
|
||||
"prettier-plugin-tailwindcss": "^0.5.11",
|
||||
"sass": "^1.71.1",
|
||||
"solid-start-node": "^0.3.10",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.1.4"
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
|
|
5897
leaky-ships/pnpm-lock.yaml
generated
5897
leaky-ships/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
39
leaky-ships/src/app.tsx
Normal file
39
leaky-ships/src/app.tsx
Normal file
|
@ -0,0 +1,39 @@
|
|||
// @refresh reload
|
||||
import "@fortawesome/fontawesome-svg-core/styles.css"
|
||||
import { Link, Meta, MetaProvider, Title } from "@solidjs/meta"
|
||||
import { Router } from "@solidjs/router"
|
||||
import { FileRoutes } from "@solidjs/start"
|
||||
import { Suspense } from "solid-js"
|
||||
import "./styles/App.scss"
|
||||
import "./styles/globals.scss"
|
||||
import "./styles/grid.scss"
|
||||
import "./styles/grid2.scss"
|
||||
import "./styles/root.css"
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<Router
|
||||
root={(props) => (
|
||||
<MetaProvider>
|
||||
<Title>Leaky Ships</Title>
|
||||
<Meta charset="utf-8" />
|
||||
<Meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<Link rel="manifest" href="/manifest.json" />
|
||||
<Link rel="icon" href="/favicon.ico" />
|
||||
<Meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<Meta name="theme-color" content="#000000" />
|
||||
<Meta
|
||||
name="description"
|
||||
content="Battleship web app with react frontend and ASP .NET backend"
|
||||
/>
|
||||
<Link rel="apple-touch-icon" href="/logo192.png" />
|
||||
|
||||
<Suspense>{props.children}</Suspense>
|
||||
</MetaProvider>
|
||||
)}
|
||||
>
|
||||
<FileRoutes />
|
||||
</Router>
|
||||
)
|
||||
}
|
|
@ -24,8 +24,8 @@ import {
|
|||
import { socket } from "~/lib/socket"
|
||||
import { modes } from "~/lib/utils/helpers"
|
||||
// import { Icons, toast } from "react-toastify"
|
||||
import { useNavigate } from "@solidjs/router"
|
||||
import { For, Show, createEffect } from "solid-js"
|
||||
import { useNavigate } from "solid-start"
|
||||
import { clearDrawing } from "~/hooks/useDraw"
|
||||
import {
|
||||
color,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// import Bluetooth from "./Bluetooth"
|
||||
// import FogImages from "./FogImages"
|
||||
// import { toast } from "react-toastify"
|
||||
import { useNavigate } from "@solidjs/router"
|
||||
import { createEffect, onCleanup } from "solid-js"
|
||||
import { useNavigate } from "solid-start"
|
||||
import BorderTiles from "~/components/Gamefield/BorderTiles"
|
||||
import EventBar from "~/components/Gamefield/EventBar"
|
||||
import HitElems from "~/components/Gamefield/HitElems"
|
||||
|
|
|
@ -2,8 +2,8 @@ import {
|
|||
faRightFromBracket,
|
||||
faSpinnerThird,
|
||||
} from "@fortawesome/pro-solid-svg-icons"
|
||||
import { useNavigate } from "@solidjs/router"
|
||||
import { JSX, Show, createEffect, createSignal, onCleanup } from "solid-js"
|
||||
import { useNavigate } from "solid-start"
|
||||
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon"
|
||||
import { full, gameProps, leave, reset, users } from "~/hooks/useGameProps"
|
||||
import { useSession } from "~/hooks/useSession"
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import classNames from "classnames"
|
||||
import { A } from "solid-start"
|
||||
|
||||
function Logo(props: { small?: boolean }) {
|
||||
return (
|
||||
<A href="/">
|
||||
<a href="/">
|
||||
<div class="relative flex flex-col items-center rounded-sm border-x-4 border-y-2 border-shield-gray bg-shield-lightgray md:border-x-8 md:border-y-4">
|
||||
<h1
|
||||
class={classNames(
|
||||
|
@ -16,7 +15,7 @@ function Logo(props: { small?: boolean }) {
|
|||
</h1>
|
||||
<Screws small={props.small} />
|
||||
</div>
|
||||
</A>
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { IconDefinition } from "@fortawesome/fontawesome-svg-core"
|
||||
import classNames from "classnames"
|
||||
import { JSX } from "solid-js"
|
||||
import { A } from "solid-start"
|
||||
import { FontAwesomeIcon } from "./FontAwesomeIcon"
|
||||
|
||||
const styles = {
|
||||
|
@ -20,7 +19,7 @@ export function OptionAnchor(props: {
|
|||
disabled?: boolean
|
||||
}) {
|
||||
return (
|
||||
<A
|
||||
<a
|
||||
class={classNames(
|
||||
styles.wrapper,
|
||||
props.disabled ? styles.disabled : styles.enabled,
|
||||
|
@ -30,7 +29,7 @@ export function OptionAnchor(props: {
|
|||
>
|
||||
<span class="mx-auto">{props.text}</span>
|
||||
<FontAwesomeIcon class={styles.icon} icon={props.icon} />
|
||||
</A>
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { drizzle } from "drizzle-orm/postgres-js"
|
|||
import postgres from "postgres"
|
||||
import * as schema from "./schemas/Tables"
|
||||
|
||||
const queryClient = postgres(process.env.DATABASE_URL ?? "")
|
||||
const queryClient = postgres(import.meta.env.VITE_DATABASE_URL ?? "")
|
||||
const db = drizzle(queryClient, {
|
||||
schema,
|
||||
})
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { mount, StartClient } from "solid-start/entry-client"
|
||||
import { mount, StartClient } from "@solidjs/start/client"
|
||||
|
||||
mount(() => <StartClient />, document)
|
||||
mount(() => <StartClient />, document.getElementById("app")!)
|
||||
|
|
|
@ -1,9 +1,20 @@
|
|||
import {
|
||||
createHandler,
|
||||
renderAsync,
|
||||
StartServer,
|
||||
} from "solid-start/entry-server"
|
||||
import { StartServer, createHandler } from "@solidjs/start/server"
|
||||
|
||||
export default createHandler(
|
||||
renderAsync((event) => <StartServer event={event} />),
|
||||
)
|
||||
export default createHandler(() => (
|
||||
<StartServer
|
||||
document={({ assets, children, scripts }) => (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
{assets}
|
||||
</head>
|
||||
<body id="app">
|
||||
{children}
|
||||
{scripts}
|
||||
</body>
|
||||
</html>
|
||||
)}
|
||||
/>
|
||||
))
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import { Session } from "@auth/core/types"
|
||||
import { getSession } from "@auth/solid-start"
|
||||
import { useIsRouting } from "@solidjs/router"
|
||||
import status from "http-status"
|
||||
import stringify from "json-stable-stringify"
|
||||
import {
|
||||
JSX,
|
||||
|
@ -8,7 +11,8 @@ import {
|
|||
createSignal,
|
||||
useContext,
|
||||
} from "solid-js"
|
||||
import { useIsRouting } from "solid-start"
|
||||
import { getRequestEvent } from "solid-js/web"
|
||||
import { authOptions } from "~/server/auth"
|
||||
import { gameProps, setGameProps, users } from "./useGameProps"
|
||||
|
||||
const [state, setState] = createSignal<Session | null | undefined>(undefined)
|
||||
|
@ -61,12 +65,17 @@ const contextValue = {
|
|||
}
|
||||
export const SessionCtx = createContext(contextValue)
|
||||
|
||||
export async function getSessionFromServer() {
|
||||
"use server"
|
||||
const event = getRequestEvent()
|
||||
if (!event) return
|
||||
const session = await getSession(event.request, authOptions)
|
||||
if (session) return session
|
||||
else return null
|
||||
}
|
||||
|
||||
export function SessionProvider(props: { children: JSX.Element }) {
|
||||
const fetchData = () =>
|
||||
fetch("/api/session").then((res) =>
|
||||
res.ok ? (res.json() as Promise<Session>) : null,
|
||||
)
|
||||
const [data, { refetch }] = createResource(fetchData)
|
||||
const [data, { refetch }] = createResource(() => getSessionFromServer())
|
||||
const isRouting = useIsRouting()
|
||||
|
||||
createEffect(() => {
|
||||
|
@ -77,8 +86,9 @@ export function SessionProvider(props: { children: JSX.Element }) {
|
|||
createEffect(() => {
|
||||
const session = data()
|
||||
const hashDiff = stringify(session) !== stringify(state())
|
||||
if (session === undefined || data.loading || !hashDiff) return
|
||||
if (!session || !hashDiff) return
|
||||
console.log("Session updated.")
|
||||
// @ts-ignore
|
||||
setState(session)
|
||||
})
|
||||
|
||||
|
@ -103,3 +113,14 @@ export function SessionProvider(props: { children: JSX.Element }) {
|
|||
}
|
||||
|
||||
export const useSession = () => useContext(SessionCtx)
|
||||
|
||||
export function isAuthenticated(res: Response) {
|
||||
switch (status[`${res.status}_CLASS`]) {
|
||||
case status.classes.SUCCESSFUL:
|
||||
case status.classes.REDIRECTION:
|
||||
return res.json()
|
||||
}
|
||||
|
||||
const resStatus = status[`${res.status}_CLASS`]
|
||||
if (typeof resStatus !== "string") return
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import status from "http-status"
|
||||
// import { toast } from "react-toastify"
|
||||
import { useNavigate } from "@solidjs/router"
|
||||
import { createEffect, createSignal, onCleanup } from "solid-js"
|
||||
import { useNavigate } from "solid-start"
|
||||
import { getPayloadFromProps } from "~/lib/getPayloadFromProps"
|
||||
import { getPayloadwithChecksum } from "~/lib/getPayloadwithChecksum"
|
||||
import { socket } from "~/lib/socket"
|
||||
import { GamePropsSchema, GameState } from "~/lib/zodSchemas"
|
||||
import { isAuthenticated } from "~/routes/start"
|
||||
import { GameSettings, PlayerEvent } from "../interfaces/frontend"
|
||||
import {
|
||||
DispatchMove,
|
||||
|
@ -20,7 +19,7 @@ import {
|
|||
setShips,
|
||||
users,
|
||||
} from "./useGameProps"
|
||||
import { useSession } from "./useSession"
|
||||
import { isAuthenticated, useSession } from "./useSession"
|
||||
|
||||
/** This function should only be called once per page, otherwise there will be multiple socket connections and duplicate event listeners. */
|
||||
function useSocket() {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Session } from "@auth/core/types"
|
||||
import http from "http"
|
||||
import type { Server as HTTPServer } from "http"
|
||||
import type { Socket as NetSocket } from "net"
|
||||
import type {
|
||||
Server as IOServer,
|
||||
Server,
|
||||
|
@ -16,10 +17,14 @@ import {
|
|||
ShipProps,
|
||||
} from "./frontend"
|
||||
|
||||
export interface SocketServer extends http.Server {
|
||||
interface SocketServer extends HTTPServer {
|
||||
io?: IOServer
|
||||
}
|
||||
|
||||
export interface SocketWithIO extends NetSocket {
|
||||
server: SocketServer
|
||||
}
|
||||
|
||||
export interface ServerToClientEvents {
|
||||
gameSetting: (payload: GameSettings, hash: string) => void
|
||||
playerEvent: (event: PlayerEvent) => void
|
|
@ -1,4 +1,4 @@
|
|||
import { APIEvent } from "solid-start"
|
||||
import { APIEvent } from "@solidjs/start/server/types"
|
||||
import { z } from "zod"
|
||||
import sendError from "./sendError"
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { APIEvent } from "@solidjs/start/server/types"
|
||||
import colors, { Color } from "colors"
|
||||
import fs from "fs"
|
||||
import { IncomingMessage } from "http"
|
||||
import { APIEvent } from "solid-start"
|
||||
|
||||
colors.enable()
|
||||
|
||||
|
|
111
leaky-ships/src/lib/backend/processRes.ts
Normal file
111
leaky-ships/src/lib/backend/processRes.ts
Normal file
|
@ -0,0 +1,111 @@
|
|||
import { and, eq, exists, ne } from "drizzle-orm"
|
||||
import db from "~/drizzle"
|
||||
import { games, user_games } from "~/drizzle/schemas/Tables"
|
||||
import { getPayloadwithChecksum } from "~/lib/getPayloadwithChecksum"
|
||||
import { GamePropsSchema } from "~/lib/zodSchemas"
|
||||
|
||||
export const gameSelects = {
|
||||
columns: {
|
||||
id: true,
|
||||
allowChat: true,
|
||||
allowMarkDraw: true,
|
||||
allowSpecials: true,
|
||||
allowSpectators: true,
|
||||
state: true,
|
||||
},
|
||||
with: {
|
||||
gamePin: {
|
||||
columns: {
|
||||
pin: true,
|
||||
},
|
||||
},
|
||||
users: {
|
||||
columns: {
|
||||
id: true,
|
||||
index: true,
|
||||
},
|
||||
with: {
|
||||
chats: {
|
||||
columns: {
|
||||
id: true,
|
||||
event: true,
|
||||
message: true,
|
||||
createdAt: true,
|
||||
},
|
||||
},
|
||||
moves: {
|
||||
columns: {
|
||||
index: true,
|
||||
type: true,
|
||||
x: true,
|
||||
y: true,
|
||||
orientation: true,
|
||||
},
|
||||
},
|
||||
ships: {
|
||||
columns: {
|
||||
size: true,
|
||||
variant: true,
|
||||
x: true,
|
||||
y: true,
|
||||
orientation: true,
|
||||
},
|
||||
},
|
||||
user: {
|
||||
columns: {
|
||||
id: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const
|
||||
|
||||
export const getGameById = async (gameId: string) => {
|
||||
return db.query.games.findFirst({
|
||||
where: and(ne(games.state, "ended"), eq(games.id, gameId)),
|
||||
...gameSelects,
|
||||
})
|
||||
}
|
||||
|
||||
export const getRunningGameToUser = async (userId: string) => {
|
||||
return db.query.games.findFirst({
|
||||
where: (game) =>
|
||||
and(
|
||||
ne(game.state, "ended"),
|
||||
exists(
|
||||
db
|
||||
.select()
|
||||
.from(user_games)
|
||||
.where(
|
||||
and(
|
||||
eq(user_games.gameId, game.id),
|
||||
eq(user_games.userId, userId),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
...gameSelects,
|
||||
})
|
||||
}
|
||||
|
||||
export function composeBody(
|
||||
gameDB: NonNullable<Awaited<ReturnType<typeof getRunningGameToUser>>>,
|
||||
): GamePropsSchema {
|
||||
const { gamePin, users, ...game } = gameDB
|
||||
const mappedUsers = users.map(({ user, ...props }) => ({
|
||||
...props,
|
||||
...user,
|
||||
}))
|
||||
const composedUsers = {
|
||||
0: mappedUsers.find((e) => e.index === 0) ?? null,
|
||||
1: mappedUsers.find((e) => e.index === 1) ?? null,
|
||||
}
|
||||
const payload = {
|
||||
game: game,
|
||||
gamePin: gamePin?.pin ?? null,
|
||||
users: composedUsers,
|
||||
}
|
||||
return getPayloadwithChecksum(payload)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { APIEvent, json } from "solid-start"
|
||||
import { APIEvent } from "@solidjs/start/server/types"
|
||||
import { rejectionError } from "./errors"
|
||||
import logging from "./logging"
|
||||
|
||||
|
@ -15,5 +15,7 @@ export default function sendError(
|
|||
)
|
||||
if ("name" in err) console.log("Sending Respons: " + err)
|
||||
// If something went wrong, let the client know with status 500
|
||||
return json(null, { status: "statusCode" in err ? err.statusCode : 500 })
|
||||
return new Response(null, {
|
||||
status: "statusCode" in err ? err.statusCode : 500,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { APIEvent, json, redirect } from "solid-start/api"
|
||||
import { redirect } from "@solidjs/router"
|
||||
import { APIEvent } from "@solidjs/start/server/types"
|
||||
import logging, { Logging } from "./logging"
|
||||
|
||||
export interface Result<T> {
|
||||
|
@ -18,6 +19,11 @@ export default function sendResponse<T>(
|
|||
return redirect(result.redirectUrl)
|
||||
} else {
|
||||
logging(result.message, result.type ?? ["debug"], request)
|
||||
return json(result.body, { status: result.statusCode ?? 200 })
|
||||
return new Response(JSON.stringify(result.body), {
|
||||
status: result.statusCode ?? 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
// @refresh reload
|
||||
import "@fortawesome/fontawesome-svg-core/styles.css"
|
||||
import { Suspense } from "solid-js"
|
||||
import {
|
||||
Body,
|
||||
ErrorBoundary,
|
||||
FileRoutes,
|
||||
Head,
|
||||
Html,
|
||||
Link,
|
||||
Meta,
|
||||
Routes,
|
||||
Scripts,
|
||||
Title,
|
||||
} from "solid-start"
|
||||
import { SessionProvider } from "./hooks/useSession"
|
||||
import "./styles/App.scss"
|
||||
import "./styles/globals.scss"
|
||||
import "./styles/grid.scss"
|
||||
import "./styles/grid2.scss"
|
||||
import "./styles/root.css"
|
||||
|
||||
export default function Root() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head>
|
||||
<Title>Leaky Ships</Title>
|
||||
<Meta charset="utf-8" />
|
||||
<Meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<Link rel="manifest" href="/manifest.json" />
|
||||
<Link rel="icon" href="/favicon.ico" />
|
||||
<Meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<Meta name="theme-color" content="#000000" />
|
||||
<Meta
|
||||
name="description"
|
||||
content="Battleship web app with react frontend and ASP .NET backend"
|
||||
/>
|
||||
<Link rel="apple-touch-icon" href="/logo192.png" />
|
||||
</Head>
|
||||
<Body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<Suspense fallback={<div>Loading</div>}>
|
||||
<ErrorBoundary>
|
||||
<SessionProvider>
|
||||
<Routes>
|
||||
<FileRoutes />
|
||||
</Routes>
|
||||
</SessionProvider>
|
||||
</ErrorBoundary>
|
||||
</Suspense>
|
||||
<Scripts />
|
||||
</Body>
|
||||
</Html>
|
||||
)
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { redirect } from "solid-start"
|
||||
import { Navigate } from "@solidjs/router"
|
||||
|
||||
export function GET() {
|
||||
return redirect("/")
|
||||
export default function NOT_FOUND() {
|
||||
return <Navigate href="/" />
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { getSession } from "@auth/solid-start"
|
||||
import { APIEvent } from "@solidjs/start/server/types"
|
||||
import { eq } from "drizzle-orm"
|
||||
import { APIEvent } from "solid-start"
|
||||
import { z } from "zod"
|
||||
import db from "~/drizzle"
|
||||
import { games } from "~/drizzle/schemas/Tables"
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
import { getSession } from "@auth/solid-start"
|
||||
import { createId } from "@paralleldrive/cuid2"
|
||||
import { APIEvent } from "@solidjs/start/server/types"
|
||||
import { eq } from "drizzle-orm"
|
||||
import { APIEvent } from "solid-start"
|
||||
import db from "~/drizzle"
|
||||
import { chats, gamepins, games, user_games } from "~/drizzle/schemas/Tables"
|
||||
import { rejectionErrors } from "~/lib/backend/errors"
|
||||
import {
|
||||
composeBody,
|
||||
gameSelects,
|
||||
getRunningGameToUser,
|
||||
} from "~/lib/backend/processRes"
|
||||
import sendResponse from "~/lib/backend/sendResponse"
|
||||
import { authOptions } from "~/server/auth"
|
||||
import { composeBody, gameSelects, getRunningGameToUser } from "./running"
|
||||
|
||||
export async function POST({ request }: APIEvent) {
|
||||
const session = await getSession(request, authOptions)
|
||||
|
@ -15,6 +19,8 @@ export async function POST({ request }: APIEvent) {
|
|||
if (!session?.user) {
|
||||
return sendResponse(request, rejectionErrors.unauthorized)
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const { email, id } = session.user
|
||||
|
||||
// Generate a random 4-digit code
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import { getSession } from "@auth/solid-start"
|
||||
import { createId } from "@paralleldrive/cuid2"
|
||||
import { APIEvent } from "@solidjs/start/server/types"
|
||||
import { and, eq } from "drizzle-orm"
|
||||
import { APIEvent } from "solid-start"
|
||||
import db from "~/drizzle"
|
||||
import { user_games } from "~/drizzle/schemas/Tables"
|
||||
import { rejectionErrors } from "~/lib/backend/errors"
|
||||
import getPinFromBody from "~/lib/backend/getPinFromBody"
|
||||
import logging from "~/lib/backend/logging"
|
||||
import { composeBody, gameSelects, getGameById } from "~/lib/backend/processRes"
|
||||
import sendError from "~/lib/backend/sendError"
|
||||
import sendResponse from "~/lib/backend/sendResponse"
|
||||
import { authOptions } from "~/server/auth"
|
||||
import { composeBody, gameSelects, getGameById } from "./running"
|
||||
|
||||
export async function POST({ request }: APIEvent) {
|
||||
const session = await getSession(request, authOptions)
|
||||
|
@ -20,6 +20,7 @@ export async function POST({ request }: APIEvent) {
|
|||
return sendResponse(request, rejectionErrors.unauthorized)
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const { email, id } = session.user
|
||||
|
||||
try {
|
||||
|
|
|
@ -1,121 +1,14 @@
|
|||
import { getSession } from "@auth/solid-start"
|
||||
import { and, eq, exists, ne, notExists } from "drizzle-orm"
|
||||
import { APIEvent } from "solid-start/api"
|
||||
import { APIEvent } from "@solidjs/start/server/types"
|
||||
import { eq, notExists } from "drizzle-orm"
|
||||
import db from "~/drizzle"
|
||||
import { games, user_games } from "~/drizzle/schemas/Tables"
|
||||
import { rejectionErrors } from "~/lib/backend/errors"
|
||||
import logging from "~/lib/backend/logging"
|
||||
import { composeBody, getRunningGameToUser } from "~/lib/backend/processRes"
|
||||
import sendResponse from "~/lib/backend/sendResponse"
|
||||
import { getPayloadwithChecksum } from "~/lib/getPayloadwithChecksum"
|
||||
import { GamePropsSchema } from "~/lib/zodSchemas"
|
||||
import { authOptions } from "~/server/auth"
|
||||
|
||||
export const gameSelects = {
|
||||
columns: {
|
||||
id: true,
|
||||
allowChat: true,
|
||||
allowMarkDraw: true,
|
||||
allowSpecials: true,
|
||||
allowSpectators: true,
|
||||
state: true,
|
||||
},
|
||||
with: {
|
||||
gamePin: {
|
||||
columns: {
|
||||
pin: true,
|
||||
},
|
||||
},
|
||||
users: {
|
||||
columns: {
|
||||
id: true,
|
||||
index: true,
|
||||
},
|
||||
with: {
|
||||
chats: {
|
||||
columns: {
|
||||
id: true,
|
||||
event: true,
|
||||
message: true,
|
||||
createdAt: true,
|
||||
},
|
||||
},
|
||||
moves: {
|
||||
columns: {
|
||||
index: true,
|
||||
type: true,
|
||||
x: true,
|
||||
y: true,
|
||||
orientation: true,
|
||||
},
|
||||
},
|
||||
ships: {
|
||||
columns: {
|
||||
size: true,
|
||||
variant: true,
|
||||
x: true,
|
||||
y: true,
|
||||
orientation: true,
|
||||
},
|
||||
},
|
||||
user: {
|
||||
columns: {
|
||||
id: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const
|
||||
|
||||
export const getGameById = async (gameId: string) => {
|
||||
return db.query.games.findFirst({
|
||||
where: and(ne(games.state, "ended"), eq(games.id, gameId)),
|
||||
...gameSelects,
|
||||
})
|
||||
}
|
||||
|
||||
export const getRunningGameToUser = async (userId: string) => {
|
||||
return db.query.games.findFirst({
|
||||
where: (game) =>
|
||||
and(
|
||||
ne(game.state, "ended"),
|
||||
exists(
|
||||
db
|
||||
.select()
|
||||
.from(user_games)
|
||||
.where(
|
||||
and(
|
||||
eq(user_games.gameId, game.id),
|
||||
eq(user_games.userId, userId),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
...gameSelects,
|
||||
})
|
||||
}
|
||||
|
||||
export function composeBody(
|
||||
gameDB: NonNullable<Awaited<ReturnType<typeof getRunningGameToUser>>>,
|
||||
): GamePropsSchema {
|
||||
const { gamePin, users, ...game } = gameDB
|
||||
const mappedUsers = users.map(({ user, ...props }) => ({
|
||||
...props,
|
||||
...user,
|
||||
}))
|
||||
const composedUsers = {
|
||||
0: mappedUsers.find((e) => e.index === 0) ?? null,
|
||||
1: mappedUsers.find((e) => e.index === 1) ?? null,
|
||||
}
|
||||
const payload = {
|
||||
game: game,
|
||||
gamePin: gamePin?.pin ?? null,
|
||||
users: composedUsers,
|
||||
}
|
||||
return getPayloadwithChecksum(payload)
|
||||
}
|
||||
|
||||
export async function GET({ request }: APIEvent) {
|
||||
const session = await getSession(request, authOptions)
|
||||
|
||||
|
@ -143,6 +36,7 @@ export async function GET({ request }: APIEvent) {
|
|||
)
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const { email, id } = session.user
|
||||
|
||||
const game = await getRunningGameToUser(id)
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
import { getSession } from "@auth/solid-start"
|
||||
import status from "http-status"
|
||||
import { APIEvent, json } from "solid-start"
|
||||
import { authOptions } from "~/server/auth"
|
||||
|
||||
export async function GET({ request }: APIEvent) {
|
||||
const session = await getSession(request, authOptions)
|
||||
if (session) return json(session)
|
||||
else return new Response(null, { status: status["UNAUTHORIZED"] })
|
||||
}
|
|
@ -1,47 +1,45 @@
|
|||
import { getSession } from "@auth/solid-start"
|
||||
import { createId } from "@paralleldrive/cuid2"
|
||||
import { APIEvent } from "@solidjs/start/server/types"
|
||||
import colors from "colors"
|
||||
import { and, eq } from "drizzle-orm"
|
||||
import status from "http-status"
|
||||
import { Server } from "socket.io"
|
||||
import { APIEvent } from "solid-start"
|
||||
import db from "~/drizzle"
|
||||
import { games, moves, ships, user_games } from "~/drizzle/schemas/Tables"
|
||||
import { SocketServer, sServer } from "~/interfaces/ApiSocket"
|
||||
import { SocketWithIO, sServer } from "~/interfaces/ApiSocket"
|
||||
import logging from "~/lib/backend/logging"
|
||||
import { GamePropsSchema } from "~/lib/zodSchemas"
|
||||
import { authOptions } from "~/server/auth"
|
||||
import {
|
||||
composeBody,
|
||||
gameSelects,
|
||||
getGameById,
|
||||
getRunningGameToUser,
|
||||
} from "./game/running"
|
||||
} from "~/lib/backend/processRes"
|
||||
import { GamePropsSchema } from "~/lib/zodSchemas"
|
||||
import { authOptions } from "~/server/auth"
|
||||
|
||||
colors.enable()
|
||||
|
||||
export async function GET({
|
||||
request,
|
||||
httpServer,
|
||||
}: APIEvent & { httpServer: SocketServer }) {
|
||||
if (httpServer.io) {
|
||||
export async function GET({ request, nativeEvent }: APIEvent) {
|
||||
const socket = nativeEvent.node.res.socket as SocketWithIO
|
||||
if (socket.server.io) {
|
||||
logging("Socket is already running " + request.url, ["infoCyan"], request)
|
||||
} else {
|
||||
logging("Socket is initializing " + request.url, ["infoCyan"], request)
|
||||
const io: sServer = new Server(httpServer, {
|
||||
const io: sServer = new Server(socket.server, {
|
||||
path: "/api/ws",
|
||||
cors: {
|
||||
origin: "https://leaky-ships.mal-noh.de",
|
||||
origin: import.meta.env.VITE_AUTH_URL,
|
||||
},
|
||||
})
|
||||
|
||||
httpServer.io = io
|
||||
socket.server.io = io
|
||||
|
||||
// io.use(authenticate)
|
||||
io.use(async (socket, next) => {
|
||||
const request = socket.request
|
||||
try {
|
||||
const url = process.env.AUTH_URL! + request.url
|
||||
const url = import.meta.env.VITE_AUTH_URL! + request.url
|
||||
const session = await getSession(
|
||||
new Request(url, {
|
||||
headers: request.headers as Record<string, string>,
|
||||
|
@ -49,6 +47,8 @@ export async function GET({
|
|||
authOptions,
|
||||
)
|
||||
if (!session) return next(new Error(status["401"]))
|
||||
|
||||
// @ts-ignore
|
||||
socket.data.user = session.user
|
||||
|
||||
const game = await getRunningGameToUser(socket.data.user?.id ?? "")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Link, Meta, Title } from "solid-start"
|
||||
import { Link, Meta, Title } from "@solidjs/meta"
|
||||
import Gamefield from "~/components/Gamefield/Gamefield"
|
||||
|
||||
export default function Home() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Link, Meta, Title } from "solid-start"
|
||||
import { Link, Meta, Title } from "@solidjs/meta"
|
||||
import Grid from "~/components/Grid"
|
||||
|
||||
export default function Home() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Link, Meta, Title } from "solid-start"
|
||||
import { Link, Meta, Title } from "@solidjs/meta"
|
||||
import Grid2 from "~/components/Grid2"
|
||||
|
||||
export default function Home() {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { A } from "solid-start"
|
||||
import BurgerMenu from "~/components/BurgerMenu"
|
||||
import Logo from "~/components/Logo"
|
||||
|
||||
|
@ -11,13 +10,13 @@ export default function Home() {
|
|||
<div class="flex h-36 w-64 items-center justify-center overflow-hidden rounded-xl border-8 border-black bg-[#2227] sm:h-48 sm:w-96 md:h-72 md:w-[32rem] md:border-[6px] xl:h-[26rem] xl:w-[48rem]">
|
||||
<video controls preload="metadata" src="/Regelwerk.mp4" />
|
||||
</div>
|
||||
<A
|
||||
<a
|
||||
id="start"
|
||||
class="font-farro rounded-lg border-b-4 border-orange-400 bg-warn px-12 pb-4 pt-5 text-2xl font-bold duration-100 active:border-b-0 active:border-t-4 sm:rounded-xl sm:border-b-[6px] sm:px-14 sm:pb-5 sm:pt-6 sm:text-3xl sm:active:border-t-[6px] md:rounded-2xl md:border-b-8 md:px-20 md:pb-6 md:pt-7 md:text-4xl md:active:border-t-8 xl:px-24 xl:pb-8 xl:pt-10 xl:text-5xl"
|
||||
href="/start"
|
||||
>
|
||||
START
|
||||
</A>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { signIn } from "@auth/solid-start/client"
|
||||
import { faLeftLong } from "@fortawesome/pro-solid-svg-icons"
|
||||
import { useNavigate, useSearchParams } from "@solidjs/router"
|
||||
import classNames from "classnames"
|
||||
import { Show, createEffect, createSignal } from "solid-js"
|
||||
import { A, useNavigate, useSearchParams } from "solid-start"
|
||||
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon"
|
||||
import { useSession } from "~/hooks/useSession"
|
||||
|
||||
|
@ -55,7 +55,7 @@ function Login() {
|
|||
if (session()) navigator("/signout")
|
||||
})
|
||||
|
||||
const login = (provider: "email" | "azure-ad") =>
|
||||
const login = (provider: "discord") =>
|
||||
signIn(provider, { email: email(), callbackUrl: "/" })
|
||||
|
||||
return (
|
||||
|
@ -85,7 +85,7 @@ function Login() {
|
|||
onSubmit={(e) => {
|
||||
e.preventDefault()
|
||||
if (!email()) return
|
||||
login("email")
|
||||
// login("email")
|
||||
}}
|
||||
>
|
||||
<label for="email" class="mx-2 text-lg">
|
||||
|
@ -130,7 +130,7 @@ function Login() {
|
|||
</a>
|
||||
<button
|
||||
id="microsoft"
|
||||
onClick={() => login("azure-ad")}
|
||||
onClick={() => login("discord")}
|
||||
class="flex w-full justify-evenly rounded-lg border border-gray-400 bg-slate-100 px-5 py-3 text-black drop-shadow-md duration-300 hover:bg-slate-200"
|
||||
>
|
||||
<img
|
||||
|
@ -147,14 +147,14 @@ function Login() {
|
|||
<Show when={errorType}>
|
||||
<hr class="mt-8 border-gray-400" />
|
||||
<div class="flex flex-col items-center">
|
||||
<A
|
||||
<a
|
||||
id="back"
|
||||
href="/"
|
||||
class="mt-10 rounded-lg border-2 border-gray-400 bg-gray-500 bg-opacity-75 px-16 py-2 text-white shadow-inner drop-shadow-md backdrop-blur-md transition-colors duration-300 hover:border-blue-600"
|
||||
>
|
||||
<FontAwesomeIcon icon={faLeftLong} />
|
||||
<span class="mx-4 font-bold">Return</span>
|
||||
</A>
|
||||
</a>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { signOut } from "@auth/solid-start/client"
|
||||
import { faLeftLong } from "@fortawesome/pro-solid-svg-icons"
|
||||
import { useNavigate } from "@solidjs/router"
|
||||
import { createEffect } from "solid-js"
|
||||
import { useNavigate } from "solid-start"
|
||||
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon"
|
||||
import { useSession } from "~/hooks/useSession"
|
||||
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
import { faEye, faLeftLong } from "@fortawesome/pro-regular-svg-icons"
|
||||
import { faPlus, faUserPlus } from "@fortawesome/pro-solid-svg-icons"
|
||||
import { GamePropsSchema } from "~/lib/zodSchemas"
|
||||
// import OtpInput from "react-otp-input"
|
||||
// import { Icons, toast } from "react-toastify"
|
||||
import status from "http-status"
|
||||
import { useNavigate, useSearchParams } from "@solidjs/router"
|
||||
import { Show, createEffect, createSignal } from "solid-js"
|
||||
import { A, useNavigate, useSearchParams } from "solid-start"
|
||||
import BurgerMenu from "~/components/BurgerMenu"
|
||||
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon"
|
||||
import Logo from "~/components/Logo"
|
||||
|
@ -15,43 +11,17 @@ import {
|
|||
OptionDiv,
|
||||
} from "~/components/OptionButton"
|
||||
import { full } from "~/hooks/useGameProps"
|
||||
import { useSession } from "~/hooks/useSession"
|
||||
|
||||
export function isAuthenticated(res: Response) {
|
||||
switch (status[`${res.status}_CLASS`]) {
|
||||
case status.classes.SUCCESSFUL:
|
||||
case status.classes.REDIRECTION:
|
||||
return res.json()
|
||||
}
|
||||
|
||||
const resStatus = status[`${res.status}_CLASS`]
|
||||
if (typeof resStatus !== "string") return
|
||||
|
||||
// toast(status[res.status], {
|
||||
// position: "top-center",
|
||||
// type: "info",
|
||||
// theme: "colored",
|
||||
// })
|
||||
}
|
||||
|
||||
// const handleConfirmation = () => {
|
||||
// const toastId = "confirm"
|
||||
// toast.warn(
|
||||
// <div id="toast-confirm">
|
||||
// <h4>You are already in another round, do you want to:</h4>
|
||||
// <button onClick={() => toast.dismiss(toastId)}>Join</button>
|
||||
// or
|
||||
// <button onClick={() => toast.dismiss(toastId)}>Leave</button>
|
||||
// </div>,
|
||||
// { autoClose: false, toastId },
|
||||
// )
|
||||
// }
|
||||
import {
|
||||
SessionProvider,
|
||||
isAuthenticated,
|
||||
useSession,
|
||||
} from "~/hooks/useSession"
|
||||
import { GamePropsSchema } from "~/lib/zodSchemas"
|
||||
|
||||
export default function Start() {
|
||||
const [otp, setOtp] = createSignal("")
|
||||
const navigator = useNavigate()
|
||||
const { session } = useSession()
|
||||
|
||||
const [searchParams] = useSearchParams()
|
||||
|
||||
const query = () => {
|
||||
|
@ -138,81 +108,83 @@ export default function Start() {
|
|||
})
|
||||
|
||||
return (
|
||||
<div class="h-full bg-theme">
|
||||
<div class="mx-auto flex h-full max-w-screen-md flex-col items-center justify-evenly">
|
||||
<Logo />
|
||||
<BurgerMenu />
|
||||
<div class="flex flex-col items-center gap-4 rounded-xl border-4 border-black bg-grayish px-6 pb-6 pt-4 shadow-lg sm:mx-8 sm:px-12 sm:pb-12 sm:pt-8 md:w-full">
|
||||
<div class="flex w-full justify-between">
|
||||
<A
|
||||
id="back"
|
||||
class="self-start rounded-lg border-b-4 border-shield-gray bg-voidDark px-8 text-2xl text-grayish duration-100 active:border-b-0 active:border-t-4 sm:rounded-xl sm:px-14 sm:py-1 sm:text-5xl"
|
||||
href="/"
|
||||
>
|
||||
<FontAwesomeIcon icon={faLeftLong} />
|
||||
</A>
|
||||
<Show when={!session()?.user?.id}>
|
||||
<A
|
||||
id="login"
|
||||
class="self-start rounded-lg border-b-4 border-orange-500 bg-yellow-500 px-4 text-2xl active:border-b-0 active:border-t-4 sm:rounded-xl sm:px-9 sm:py-2 sm:text-4xl"
|
||||
href="/signin"
|
||||
<SessionProvider>
|
||||
<div class="h-full bg-theme">
|
||||
<div class="mx-auto flex h-full max-w-screen-md flex-col items-center justify-evenly">
|
||||
<Logo />
|
||||
<BurgerMenu />
|
||||
<div class="flex flex-col items-center gap-4 rounded-xl border-4 border-black bg-grayish px-6 pb-6 pt-4 shadow-lg sm:mx-8 sm:px-12 sm:pb-12 sm:pt-8 md:w-full">
|
||||
<div class="flex w-full justify-between">
|
||||
<a
|
||||
id="back"
|
||||
class="self-start rounded-lg border-b-4 border-shield-gray bg-voidDark px-8 text-2xl text-grayish duration-100 active:border-b-0 active:border-t-4 sm:rounded-xl sm:px-14 sm:py-1 sm:text-5xl"
|
||||
href="/"
|
||||
>
|
||||
Login
|
||||
</A>
|
||||
</Show>
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-6 sm:gap-12">
|
||||
<OptionButton
|
||||
text="Raum erstellen"
|
||||
callback={gameFetch}
|
||||
icon={faPlus}
|
||||
disabled={!session()}
|
||||
/>
|
||||
<Show
|
||||
when={query().join && !!session()}
|
||||
fallback={
|
||||
<OptionAnchor
|
||||
text="Raum beitreten"
|
||||
href="?q=join"
|
||||
icon={faUserPlus}
|
||||
disabled={!session()}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<OptionDiv icon={faUserPlus}>
|
||||
<input
|
||||
disabled={!session()}
|
||||
value={otp()}
|
||||
onInput={(e) =>
|
||||
setOtp((otp) => {
|
||||
const value = e.target.value
|
||||
return /^\d{0,4}$/.test(value) ? value : otp
|
||||
})
|
||||
}
|
||||
/>
|
||||
</OptionDiv>
|
||||
</Show>
|
||||
<Show
|
||||
when={query().watch}
|
||||
fallback={
|
||||
<OptionAnchor text="Zuschauen" icon={faEye} href="?q=watch" />
|
||||
}
|
||||
>
|
||||
<OptionDiv icon={faEye}>
|
||||
<input
|
||||
value={otp()}
|
||||
onInput={(e) =>
|
||||
setOtp((otp) => {
|
||||
const value = e.target.value
|
||||
return /^\d{0,4}$/.test(value) ? value : otp
|
||||
})
|
||||
}
|
||||
/>
|
||||
</OptionDiv>
|
||||
</Show>
|
||||
<FontAwesomeIcon icon={faLeftLong} />
|
||||
</a>
|
||||
<Show when={!session()?.user?.id}>
|
||||
<a
|
||||
id="login"
|
||||
class="self-start rounded-lg border-b-4 border-orange-500 bg-yellow-500 px-4 text-2xl active:border-b-0 active:border-t-4 sm:rounded-xl sm:px-9 sm:py-2 sm:text-4xl"
|
||||
href="/signin"
|
||||
>
|
||||
Login
|
||||
</a>
|
||||
</Show>
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-6 sm:gap-12">
|
||||
<OptionButton
|
||||
text="Raum erstellen"
|
||||
callback={gameFetch}
|
||||
icon={faPlus}
|
||||
disabled={!session()}
|
||||
/>
|
||||
<Show
|
||||
when={query().join && !!session()}
|
||||
fallback={
|
||||
<OptionAnchor
|
||||
text="Raum beitreten"
|
||||
href="?q=join"
|
||||
icon={faUserPlus}
|
||||
disabled={!session()}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<OptionDiv icon={faUserPlus}>
|
||||
<input
|
||||
disabled={!session()}
|
||||
value={otp()}
|
||||
onInput={(e) =>
|
||||
setOtp((otp) => {
|
||||
const value = e.target.value
|
||||
return /^\d{0,4}$/.test(value) ? value : otp
|
||||
})
|
||||
}
|
||||
/>
|
||||
</OptionDiv>
|
||||
</Show>
|
||||
<Show
|
||||
when={query().watch}
|
||||
fallback={
|
||||
<OptionAnchor text="Zuschauen" icon={faEye} href="?q=watch" />
|
||||
}
|
||||
>
|
||||
<OptionDiv icon={faEye}>
|
||||
<input
|
||||
value={otp()}
|
||||
onInput={(e) =>
|
||||
setOtp((otp) => {
|
||||
const value = e.target.value
|
||||
return /^\d{0,4}$/.test(value) ? value : otp
|
||||
})
|
||||
}
|
||||
/>
|
||||
</OptionDiv>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SessionProvider>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import AzureADProvider from "@auth/core/providers/azure-ad"
|
||||
import EmailProvider from "@auth/core/providers/email"
|
||||
import Discord from "@auth/core/providers/discord"
|
||||
import { DrizzleAdapter } from "@auth/drizzle-adapter"
|
||||
import { type SolidAuthConfig } from "@auth/solid-start"
|
||||
import {
|
||||
|
@ -20,19 +19,14 @@ const customConfig: Config = {
|
|||
|
||||
export const authOptions: SolidAuthConfig = {
|
||||
providers: [
|
||||
// @ts-expect-error Types are wrong
|
||||
EmailProvider({
|
||||
server: process.env.EMAIL_SERVER,
|
||||
from: process.env.EMAIL_FROM,
|
||||
}),
|
||||
AzureADProvider({
|
||||
clientId: process.env.AZURE_AD_CLIENT_ID ?? "",
|
||||
clientSecret: process.env.AZURE_AD_CLIENT_SECRET ?? "",
|
||||
tenantId: process.env.AZURE_AD_TENANT_ID,
|
||||
// @ts-ignore
|
||||
Discord({
|
||||
clientId: import.meta.env.VITE_DISCORD_CLIENT_ID,
|
||||
clientSecret: import.meta.env.VITE_DISCORD_CLIENT_SECRET,
|
||||
}),
|
||||
],
|
||||
adapter: DrizzleAdapter(db),
|
||||
secret: process.env.AUTH_SECRET,
|
||||
secret: import.meta.env.VITE_AUTH_SECRET,
|
||||
callbacks: {
|
||||
signIn: ({ user, account }) => {
|
||||
// Custom signIn callback to add username to email provider
|
||||
|
@ -43,6 +37,7 @@ export const authOptions: SolidAuthConfig = {
|
|||
},
|
||||
session: ({ session, user }) => {
|
||||
if (session?.user) {
|
||||
// @ts-ignore
|
||||
session.user.id = user.id
|
||||
}
|
||||
return session
|
||||
|
|
16
leaky-ships/src/types/env.d.ts
vendored
Normal file
16
leaky-ships/src/types/env.d.ts
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
/// <reference types="vinxi/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_DISCORD_CLIENT_ID: string
|
||||
readonly VITE_DISCORD_CLIENT_SECRET: string
|
||||
|
||||
readonly VITE_AUTH_SECRET: string
|
||||
readonly VITE_AUTH_URL: string | undefined
|
||||
|
||||
readonly VITE_DATABASE_URL: string
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"include": [".eslintrc.cjs"]
|
||||
}
|
|
@ -1,15 +1,17 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"jsxImportSource": "solid-js",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "solid-js",
|
||||
"allowJs": true,
|
||||
"strict": true,
|
||||
"types": ["solid-start/env"],
|
||||
"baseUrl": "./",
|
||||
"noEmit": true,
|
||||
"types": ["vinxi/client"],
|
||||
"isolatedModules": true,
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
}
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
import solid from "solid-start/vite"
|
||||
import { defineConfig } from "vite"
|
||||
import { defineConfig } from "@solidjs/start/config"
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [solid({ ssr: false })],
|
||||
server: {
|
||||
host: "0.0.0.0",
|
||||
strictPort: true,
|
||||
},
|
||||
})
|
||||
export default defineConfig({})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue