diff options
| -rw-r--r-- | backend/go.mod | 1 | ||||
| -rw-r--r-- | backend/go.sum | 2 | ||||
| -rw-r--r-- | backend/handlers/user.go | 40 | ||||
| -rw-r--r-- | backend/main.go | 28 | ||||
| -rw-r--r-- | frontend/package-lock.json | 6 | ||||
| -rw-r--r-- | frontend/package.json | 1 | ||||
| -rw-r--r-- | frontend/src/components/UploadRunDialog.tsx | 99 |
7 files changed, 106 insertions, 71 deletions
diff --git a/backend/go.mod b/backend/go.mod index f6eef48..ae50685 100644 --- a/backend/go.mod +++ b/backend/go.mod | |||
| @@ -8,6 +8,7 @@ require ( | |||
| 8 | ) | 8 | ) |
| 9 | 9 | ||
| 10 | require ( | 10 | require ( |
| 11 | github.com/gin-contrib/cors v1.7.2 | ||
| 11 | github.com/golang-jwt/jwt/v4 v4.5.0 | 12 | github.com/golang-jwt/jwt/v4 v4.5.0 |
| 12 | github.com/google/uuid v1.6.0 | 13 | github.com/google/uuid v1.6.0 |
| 13 | github.com/pektezol/steam_go v1.1.2 | 14 | github.com/pektezol/steam_go v1.1.2 |
diff --git a/backend/go.sum b/backend/go.sum index 10504e4..f117b31 100644 --- a/backend/go.sum +++ b/backend/go.sum | |||
| @@ -31,6 +31,8 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2 | |||
| 31 | github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= | 31 | github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= |
| 32 | github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= | 32 | github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= |
| 33 | github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= | 33 | github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= |
| 34 | github.com/gin-contrib/cors v1.7.2 h1:oLDHxdg8W/XDoN/8zamqk/Drgt4oVZDvaV0YmvVICQw= | ||
| 35 | github.com/gin-contrib/cors v1.7.2/go.mod h1:SUJVARKgQ40dmrzgXEVxj2m7Ig1v1qIboQkPDTQ9t2E= | ||
| 34 | github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= | 36 | github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= |
| 35 | github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= | 37 | github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= |
| 36 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= | 38 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= |
diff --git a/backend/handlers/user.go b/backend/handlers/user.go index 908063f..17a7819 100644 --- a/backend/handlers/user.go +++ b/backend/handlers/user.go | |||
| @@ -301,10 +301,12 @@ func Profile(c *gin.Context) { | |||
| 301 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 301 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 302 | return | 302 | return |
| 303 | } | 303 | } |
| 304 | sql = `WITH best_scores AS (SELECT sp.user_id, sp.map_id, MIN(sp.score_count) AS best_score_count, MIN(sp.score_time) AS best_score_time | 304 | sql = `WITH best_scores AS (WITH RankedScores AS (SELECT sp.user_id, sp.map_id, sp.score_count, sp.score_time, ROW_NUMBER() OVER ( |
| 305 | FROM records_sp sp WHERE sp.is_deleted = false GROUP BY sp.user_id, sp.map_id) | 305 | PARTITION BY sp.user_id, sp.map_id ORDER BY sp.score_count ASC, sp.score_time ASC) AS rank FROM records_sp sp WHERE sp.is_deleted = false) |
| 306 | SELECT (SELECT COUNT(*) + 1 FROM best_scores AS inner_scores WHERE inner_scores.map_id = bs.map_id AND (inner_scores.best_score_count < bs.best_score_count OR (inner_scores.best_score_count = bs.best_score_count AND inner_scores.best_score_time < bs.best_score_time))) AS placement | 306 | SELECT user_id, map_id, score_count AS best_score_count, score_time AS best_score_time FROM RankedScores WHERE rank = 1) |
| 307 | FROM best_scores AS bs WHERE bs.user_id = $1 ORDER BY map_id, placement` | 307 | SELECT (SELECT COUNT(*) + 1 FROM best_scores AS inner_scores WHERE inner_scores.map_id = bs.map_id |
| 308 | AND (inner_scores.best_score_count < bs.best_score_count OR (inner_scores.best_score_count = bs.best_score_count | ||
| 309 | AND inner_scores.best_score_time < bs.best_score_time))) AS placement FROM best_scores AS bs WHERE bs.user_id = $1 ORDER BY map_id, placement` | ||
| 308 | placementsRows, err := database.DB.Query(sql, user.(models.User).SteamID) | 310 | placementsRows, err := database.DB.Query(sql, user.(models.User).SteamID) |
| 309 | if err != nil { | 311 | if err != nil { |
| 310 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 312 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| @@ -355,10 +357,12 @@ func Profile(c *gin.Context) { | |||
| 355 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 357 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 356 | return | 358 | return |
| 357 | } | 359 | } |
| 358 | sql = `WITH best_scores AS (SELECT mp.host_id, mp.partner_id, mp.map_id, MIN(mp.score_count) AS best_score_count, MIN(mp.score_time) AS best_score_time | 360 | sql = `WITH best_scores AS (WITH RankedScores AS (SELECT mp.host_id, mp.partner_id, mp.map_id, mp.score_count, mp.score_time, ROW_NUMBER() OVER ( |
| 359 | FROM records_mp mp WHERE mp.is_deleted = false GROUP BY mp.host_id, mp.partner_id, mp.map_id) | 361 | PARTITION BY mp.host_id, mp.partner_id, mp.map_id ORDER BY mp.score_count ASC, mp.score_time ASC) AS rank FROM records_mp mp WHERE mp.is_deleted = false) |
| 360 | SELECT (SELECT COUNT(*) + 1 FROM best_scores AS inner_scores WHERE inner_scores.map_id = bs.map_id AND (inner_scores.best_score_count < bs.best_score_count OR (inner_scores.best_score_count = bs.best_score_count AND inner_scores.best_score_time < bs.best_score_time))) AS placement | 362 | SELECT host_id, partner_id, map_id, score_count AS best_score_count, score_time AS best_score_time FROM RankedScores WHERE rank = 1) |
| 361 | FROM best_scores AS bs WHERE bs.host_id = $1 or bs.partner_id = $1 ORDER BY map_id, placement` | 363 | SELECT (SELECT COUNT(*) + 1 FROM best_scores AS inner_scores WHERE inner_scores.map_id = bs.map_id |
| 364 | AND (inner_scores.best_score_count < bs.best_score_count OR (inner_scores.best_score_count = bs.best_score_count | ||
| 365 | AND inner_scores.best_score_time < bs.best_score_time))) AS placement FROM best_scores AS bs WHERE bs.host_id = $1 or bs.partner_id = $1 ORDER BY map_id, placement` | ||
| 362 | placementsRows, err = database.DB.Query(sql, user.(models.User).SteamID) | 366 | placementsRows, err = database.DB.Query(sql, user.(models.User).SteamID) |
| 363 | if err != nil { | 367 | if err != nil { |
| 364 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 368 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| @@ -675,10 +679,12 @@ func FetchUser(c *gin.Context) { | |||
| 675 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 679 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 676 | return | 680 | return |
| 677 | } | 681 | } |
| 678 | sql = `WITH best_scores AS (SELECT sp.user_id, sp.map_id, MIN(sp.score_count) AS best_score_count, MIN(sp.score_time) AS best_score_time | 682 | sql = `WITH best_scores AS (WITH RankedScores AS (SELECT sp.user_id, sp.map_id, sp.score_count, sp.score_time, ROW_NUMBER() OVER ( |
| 679 | FROM records_sp sp WHERE sp.is_deleted = false GROUP BY sp.user_id, sp.map_id) | 683 | PARTITION BY sp.user_id, sp.map_id ORDER BY sp.score_count ASC, sp.score_time ASC) AS rank FROM records_sp sp WHERE sp.is_deleted = false) |
| 680 | SELECT (SELECT COUNT(*) + 1 FROM best_scores AS inner_scores WHERE inner_scores.map_id = bs.map_id AND (inner_scores.best_score_count < bs.best_score_count OR (inner_scores.best_score_count = bs.best_score_count AND inner_scores.best_score_time < bs.best_score_time))) AS placement | 684 | SELECT user_id, map_id, score_count AS best_score_count, score_time AS best_score_time FROM RankedScores WHERE rank = 1) |
| 681 | FROM best_scores AS bs WHERE bs.user_id = $1 ORDER BY map_id, placement` | 685 | SELECT (SELECT COUNT(*) + 1 FROM best_scores AS inner_scores WHERE inner_scores.map_id = bs.map_id |
| 686 | AND (inner_scores.best_score_count < bs.best_score_count OR (inner_scores.best_score_count = bs.best_score_count | ||
| 687 | AND inner_scores.best_score_time < bs.best_score_time))) AS placement FROM best_scores AS bs WHERE bs.user_id = $1 ORDER BY map_id, placement` | ||
| 682 | placementsRows, err := database.DB.Query(sql, user.SteamID) | 688 | placementsRows, err := database.DB.Query(sql, user.SteamID) |
| 683 | if err != nil { | 689 | if err != nil { |
| 684 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 690 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| @@ -729,10 +735,12 @@ func FetchUser(c *gin.Context) { | |||
| 729 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 735 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
| 730 | return | 736 | return |
| 731 | } | 737 | } |
| 732 | sql = `WITH best_scores AS (SELECT mp.host_id, mp.partner_id, mp.map_id, MIN(mp.score_count) AS best_score_count, MIN(mp.score_time) AS best_score_time | 738 | sql = `WITH best_scores AS (WITH RankedScores AS (SELECT mp.host_id, mp.partner_id, mp.map_id, mp.score_count, mp.score_time, ROW_NUMBER() OVER ( |
| 733 | FROM records_mp mp WHERE mp.is_deleted = false GROUP BY mp.host_id, mp.partner_id, mp.map_id) | 739 | PARTITION BY mp.host_id, mp.partner_id, mp.map_id ORDER BY mp.score_count ASC, mp.score_time ASC) AS rank FROM records_mp mp WHERE mp.is_deleted = false) |
| 734 | SELECT (SELECT COUNT(*) + 1 FROM best_scores AS inner_scores WHERE inner_scores.map_id = bs.map_id AND (inner_scores.best_score_count < bs.best_score_count OR (inner_scores.best_score_count = bs.best_score_count AND inner_scores.best_score_time < bs.best_score_time))) AS placement | 740 | SELECT host_id, partner_id, map_id, score_count AS best_score_count, score_time AS best_score_time FROM RankedScores WHERE rank = 1) |
| 735 | FROM best_scores AS bs WHERE bs.host_id = $1 or bs.partner_id = $1 ORDER BY map_id, placement` | 741 | SELECT (SELECT COUNT(*) + 1 FROM best_scores AS inner_scores WHERE inner_scores.map_id = bs.map_id |
| 742 | AND (inner_scores.best_score_count < bs.best_score_count OR (inner_scores.best_score_count = bs.best_score_count | ||
| 743 | AND inner_scores.best_score_time < bs.best_score_time))) AS placement FROM best_scores AS bs WHERE bs.host_id = $1 or bs.partner_id = $1 ORDER BY map_id, placement` | ||
| 736 | placementsRows, err = database.DB.Query(sql, user.SteamID) | 744 | placementsRows, err = database.DB.Query(sql, user.SteamID) |
| 737 | if err != nil { | 745 | if err != nil { |
| 738 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) | 746 | c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) |
diff --git a/backend/main.go b/backend/main.go index a50be7e..6499b51 100644 --- a/backend/main.go +++ b/backend/main.go | |||
| @@ -4,11 +4,13 @@ import ( | |||
| 4 | "fmt" | 4 | "fmt" |
| 5 | "log" | 5 | "log" |
| 6 | "os" | 6 | "os" |
| 7 | "time" | ||
| 7 | 8 | ||
| 8 | "lphub/api" | 9 | "lphub/api" |
| 9 | "lphub/database" | 10 | "lphub/database" |
| 10 | _ "lphub/docs" | 11 | _ "lphub/docs" |
| 11 | 12 | ||
| 13 | "github.com/gin-contrib/cors" | ||
| 12 | "github.com/gin-gonic/gin" | 14 | "github.com/gin-gonic/gin" |
| 13 | "github.com/joho/godotenv" | 15 | "github.com/joho/godotenv" |
| 14 | ) | 16 | ) |
| @@ -34,19 +36,19 @@ func main() { | |||
| 34 | database.ConnectDB() | 36 | database.ConnectDB() |
| 35 | api.InitRoutes(router) | 37 | api.InitRoutes(router) |
| 36 | // for debugging | 38 | // for debugging |
| 37 | // router.Use(cors.New(cors.Config{ | 39 | router.Use(cors.New(cors.Config{ |
| 38 | // AllowOrigins: []string{"*"}, | 40 | AllowOrigins: []string{"*"}, |
| 39 | // AllowMethods: []string{"GET", "POST", "DELETE", "PUT", "PATCH"}, | 41 | AllowMethods: []string{"GET", "POST", "DELETE", "PUT", "PATCH"}, |
| 40 | // AllowHeaders: []string{"Origin"}, | 42 | AllowHeaders: []string{"Origin"}, |
| 41 | // ExposeHeaders: []string{"Content-Length"}, | 43 | ExposeHeaders: []string{"Content-Length"}, |
| 42 | // AllowCredentials: true, | 44 | AllowCredentials: true, |
| 43 | // MaxAge: 12 * time.Hour, | 45 | MaxAge: 12 * time.Hour, |
| 44 | // })) | 46 | })) |
| 45 | // router.Static("/static", "../frontend/build/static") | 47 | router.Static("/static", "../frontend/build/static") |
| 46 | // router.StaticFile("/", "../frontend/build/index.html") | 48 | router.StaticFile("/", "../frontend/build/index.html") |
| 47 | // router.NoRoute(func(c *gin.Context) { | 49 | router.NoRoute(func(c *gin.Context) { |
| 48 | // c.File("../frontend/build/index.html") | 50 | c.File("../frontend/build/index.html") |
| 49 | // }) | 51 | }) |
| 50 | router.MaxMultipartMemory = 200 << 20 // 200 mb limit for demos | 52 | router.MaxMultipartMemory = 200 << 20 // 200 mb limit for demos |
| 51 | router.Run(fmt.Sprintf(":%s", os.Getenv("PORT"))) | 53 | router.Run(fmt.Sprintf(":%s", os.Getenv("PORT"))) |
| 52 | } | 54 | } |
diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8b901ad..a77d244 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | "name": "frontend", | 8 | "name": "frontend", |
| 9 | "version": "0.1.0", | 9 | "version": "0.1.0", |
| 10 | "dependencies": { | 10 | "dependencies": { |
| 11 | "@nekz/sdp": "^0.9.0", | ||
| 11 | "@testing-library/jest-dom": "^5.17.0", | 12 | "@testing-library/jest-dom": "^5.17.0", |
| 12 | "@testing-library/react": "^13.4.0", | 13 | "@testing-library/react": "^13.4.0", |
| 13 | "@testing-library/user-event": "^13.5.0", | 14 | "@testing-library/user-event": "^13.5.0", |
| @@ -3174,6 +3175,11 @@ | |||
| 3174 | "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", | 3175 | "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", |
| 3175 | "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==" | 3176 | "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==" |
| 3176 | }, | 3177 | }, |
| 3178 | "node_modules/@nekz/sdp": { | ||
| 3179 | "version": "0.9.0", | ||
| 3180 | "resolved": "https://registry.npmjs.org/@nekz/sdp/-/sdp-0.9.0.tgz", | ||
| 3181 | "integrity": "sha512-ndg3Ze/RZxsyX0QRhZ0HnkHUIth7/3jpTcABhzQzsXV0Y4MzpoZ0dj6KRqiBz+O3acZdk0/9gr40Smqc7S4ikg==" | ||
| 3182 | }, | ||
| 3177 | "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { | 3183 | "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { |
| 3178 | "version": "5.1.1-v1", | 3184 | "version": "5.1.1-v1", |
| 3179 | "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", | 3185 | "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", |
diff --git a/frontend/package.json b/frontend/package.json index 6c3022d..57c92a7 100644 --- a/frontend/package.json +++ b/frontend/package.json | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | "version": "0.1.0", | 3 | "version": "0.1.0", |
| 4 | "private": true, | 4 | "private": true, |
| 5 | "dependencies": { | 5 | "dependencies": { |
| 6 | "@nekz/sdp": "^0.9.0", | ||
| 6 | "@testing-library/jest-dom": "^5.17.0", | 7 | "@testing-library/jest-dom": "^5.17.0", |
| 7 | "@testing-library/react": "^13.4.0", | 8 | "@testing-library/react": "^13.4.0", |
| 8 | "@testing-library/user-event": "^13.5.0", | 9 | "@testing-library/user-event": "^13.5.0", |
diff --git a/frontend/src/components/UploadRunDialog.tsx b/frontend/src/components/UploadRunDialog.tsx index d42ffe7..9f417b5 100644 --- a/frontend/src/components/UploadRunDialog.tsx +++ b/frontend/src/components/UploadRunDialog.tsx | |||
| @@ -1,11 +1,16 @@ | |||
| 1 | import React from 'react'; | 1 | import React from 'react'; |
| 2 | import { UploadRunContent } from '../types/Content'; | 2 | import { UploadRunContent } from '../types/Content'; |
| 3 | import { DemoMessages, ScoreboardTempUpdate, SourceDemoParser, UserMessage } from '@nekz/sdp'; | ||
| 4 | import fs from 'fs'; | ||
| 5 | |||
| 6 | |||
| 3 | 7 | ||
| 4 | import '../css/UploadRunDialog.css'; | 8 | import '../css/UploadRunDialog.css'; |
| 5 | import { Game } from '../types/Game'; | 9 | import { Game } from '../types/Game'; |
| 6 | import { Map } from '../types/Map'; | 10 | import { Map } from '../types/Map'; |
| 7 | import { API } from '../api/Api'; | 11 | import { API } from '../api/Api'; |
| 8 | import { useNavigate } from 'react-router-dom'; | 12 | import { useNavigate } from 'react-router-dom'; |
| 13 | import { SvcUserMessage } from '@nekz/sdp/script/src/types/NetMessages'; | ||
| 9 | 14 | ||
| 10 | interface UploadRunDialogProps { | 15 | interface UploadRunDialogProps { |
| 11 | token?: string; | 16 | token?: string; |
| @@ -103,6 +108,16 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose, | |||
| 103 | return | 108 | return |
| 104 | } | 109 | } |
| 105 | } | 110 | } |
| 111 | const demo = SourceDemoParser.default() | ||
| 112 | .setOptions({ packets: true }) | ||
| 113 | .parse(await uploadRunContent.host_demo.arrayBuffer()); | ||
| 114 | |||
| 115 | const scoreboardPacket = demo.findPacket(ScoreboardTempUpdate) | ||
| 116 | if (scoreboardPacket) { | ||
| 117 | console.log(scoreboardPacket) | ||
| 118 | } else { | ||
| 119 | console.log("couldnt find scoreboard packet") | ||
| 120 | } | ||
| 106 | if (window.confirm("Are you sure you want to submit this run to LPHUB?")) { | 121 | if (window.confirm("Are you sure you want to submit this run to LPHUB?")) { |
| 107 | const message = await API.post_record(token, uploadRunContent); | 122 | const message = await API.post_record(token, uploadRunContent); |
| 108 | alert(message); | 123 | alert(message); |
| @@ -114,7 +129,7 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose, | |||
| 114 | 129 | ||
| 115 | React.useEffect(() => { | 130 | React.useEffect(() => { |
| 116 | if (open) { | 131 | if (open) { |
| 117 | _handle_game_select("1", "Portal 2 - Singleplayer"); // a different approach?. | 132 | _handle_game_select("1", "Portal 2 - Singleplayer"); // a different approach?. |
| 118 | } | 133 | } |
| 119 | }, [open]); | 134 | }, [open]); |
| 120 | 135 | ||
| @@ -125,15 +140,15 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose, | |||
| 125 | <div id='upload-run-menu'> | 140 | <div id='upload-run-menu'> |
| 126 | <div id='upload-run-menu-add'> | 141 | <div id='upload-run-menu-add'> |
| 127 | <div id='upload-run-route-category'> | 142 | <div id='upload-run-route-category'> |
| 128 | <div style={{padding: "15px 0px"}} className='upload-run-dropdown-container'> | 143 | <div style={{ padding: "15px 0px" }} className='upload-run-dropdown-container'> |
| 129 | <h1 style={{paddingBottom: "14px"}}>Select Game</h1> | 144 | <h1 style={{ paddingBottom: "14px" }}>Select Game</h1> |
| 130 | <div onClick={() => _handle_dropdowns(1)} style={{display: "flex", alignItems: "center", cursor: "pointer", justifyContent: "space-between"}}> | 145 | <div onClick={() => _handle_dropdowns(1)} style={{ display: "flex", alignItems: "center", cursor: "pointer", justifyContent: "space-between" }}> |
| 131 | <div className='dropdown-cur'>{selectedGameName}</div> | 146 | <div className='dropdown-cur'>{selectedGameName}</div> |
| 132 | <i style={{rotate: "-90deg", transform: "translate(-5px, 10px)"}} className="triangle"></i> | 147 | <i style={{ rotate: "-90deg", transform: "translate(-5px, 10px)" }} className="triangle"></i> |
| 133 | </div> | 148 | </div> |
| 134 | <div className={dropdown1Vis ? "upload-run-dropdown" : "upload-run-dropdown hidden"}> | 149 | <div className={dropdown1Vis ? "upload-run-dropdown" : "upload-run-dropdown hidden"}> |
| 135 | {games.map((game) => ( | 150 | {games.map((game) => ( |
| 136 | <div onClick={() => {_handle_game_select(game.id.toString(), game.name); _handle_dropdowns(1)}} key={game.id}>{game.name}</div> | 151 | <div onClick={() => { _handle_game_select(game.id.toString(), game.name); _handle_dropdowns(1) }} key={game.id}>{game.name}</div> |
| 137 | ))} | 152 | ))} |
| 138 | </div> | 153 | </div> |
| 139 | </div> | 154 | </div> |
| @@ -141,45 +156,45 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose, | |||
| 141 | !loading && | 156 | !loading && |
| 142 | ( | 157 | ( |
| 143 | <> | 158 | <> |
| 144 | <div className='upload-run-map-container' style={{paddingBottom: "10px"}}> | 159 | <div className='upload-run-map-container' style={{ paddingBottom: "10px" }}> |
| 145 | <div style={{padding: "15px 0px"}}> | 160 | <div style={{ padding: "15px 0px" }}> |
| 146 | <h1 style={{paddingBottom: "14px"}}>Select Map</h1> | 161 | <h1 style={{ paddingBottom: "14px" }}>Select Map</h1> |
| 147 | <div onClick={() => _handle_dropdowns(2)} style={{display: "flex", alignItems: "center", cursor: "pointer", justifyContent: "space-between"}}> | 162 | <div onClick={() => _handle_dropdowns(2)} style={{ display: "flex", alignItems: "center", cursor: "pointer", justifyContent: "space-between" }}> |
| 148 | <span style={{userSelect: "none"}}>{currentMap}</span> | 163 | <span style={{ userSelect: "none" }}>{currentMap}</span> |
| 149 | <i style={{rotate: "-90deg", transform: "translate(-5px, 10px)"}} className="triangle"></i> | 164 | <i style={{ rotate: "-90deg", transform: "translate(-5px, 10px)" }} className="triangle"></i> |
| 165 | </div> | ||
| 150 | </div> | 166 | </div> |
| 151 | </div> | 167 | <div> |
| 152 | <div> | 168 | <div id='dropdown2' className={dropdown2Vis ? "upload-run-dropdown" : "upload-run-dropdown hidden"}> |
| 153 | <div id='dropdown2' className={dropdown2Vis ? "upload-run-dropdown" : "upload-run-dropdown hidden"}> | 169 | {selectedGameMaps && selectedGameMaps.map((gameMap) => ( |
| 154 | {selectedGameMaps && selectedGameMaps.map((gameMap) => ( | 170 | <div onClick={() => { setUploadRunContent({ ...uploadRunContent, map_id: gameMap.id }); _set_current_map(gameMap.name); _handle_dropdowns(2); }} key={gameMap.id}>{gameMap.name}</div> |
| 155 | <div onClick={() => { setUploadRunContent({...uploadRunContent, map_id: gameMap.id}); _set_current_map(gameMap.name); _handle_dropdowns(2); }} key={gameMap.id}>{gameMap.name}</div> | 171 | ))} |
| 156 | ))} | 172 | </div> |
| 173 | </div> | ||
| 174 | <span>Host Demo</span> | ||
| 175 | <input type="file" name="host_demo" id="host_demo" accept=".dem" onChange={(e) => _handle_file_change(e, true)} /> | ||
| 176 | { | ||
| 177 | games[selectedGameID].is_coop && | ||
| 178 | ( | ||
| 179 | <> | ||
| 180 | <span>Partner Demo</span> | ||
| 181 | <input type="file" name="partner_demo" id="partner_demo" accept=".dem" onChange={(e) => _handle_file_change(e, false)} /> | ||
| 182 | <span>Partner ID</span> | ||
| 183 | <input type="text" name="partner_id" id="partner_id" onChange={(e) => setUploadRunContent({ | ||
| 184 | ...uploadRunContent, | ||
| 185 | partner_id: e.target.value, | ||
| 186 | })} /> | ||
| 187 | </> | ||
| 188 | ) | ||
| 189 | } | ||
| 190 | <div className='search-container'> | ||
| 191 | |||
| 192 | </div> | ||
| 193 | <div className='upload-run-buttons-container'> | ||
| 194 | <button onClick={_upload_run}>Submit</button> | ||
| 195 | <button onClick={() => onClose()}>Cancel</button> | ||
| 157 | </div> | 196 | </div> |
| 158 | </div> | 197 | </div> |
| 159 | <span>Host Demo</span> | ||
| 160 | <input type="file" name="host_demo" id="host_demo" accept=".dem" onChange={(e) => _handle_file_change(e, true)} /> | ||
| 161 | { | ||
| 162 | games[selectedGameID].is_coop && | ||
| 163 | ( | ||
| 164 | <> | ||
| 165 | <span>Partner Demo</span> | ||
| 166 | <input type="file" name="partner_demo" id="partner_demo" accept=".dem" onChange={(e) => _handle_file_change(e, false)} /> | ||
| 167 | <span>Partner ID</span> | ||
| 168 | <input type="text" name="partner_id" id="partner_id" onChange={(e) => setUploadRunContent({ | ||
| 169 | ...uploadRunContent, | ||
| 170 | partner_id: e.target.value, | ||
| 171 | })} /> | ||
| 172 | </> | ||
| 173 | ) | ||
| 174 | } | ||
| 175 | <div className='search-container'> | ||
| 176 | |||
| 177 | </div> | ||
| 178 | <div className='upload-run-buttons-container'> | ||
| 179 | <button onClick={_upload_run}>Submit</button> | ||
| 180 | <button onClick={() => onClose()}>Cancel</button> | ||
| 181 | </div> | ||
| 182 | </div> | ||
| 183 | </> | 198 | </> |
| 184 | ) | 199 | ) |
| 185 | } | 200 | } |