From 64cfcb118da87caf41b021a6e326a5990a643973 Mon Sep 17 00:00:00 2001 From: Anze Demsar Date: Sat, 30 Sep 2023 10:03:17 +0200 Subject: [PATCH 1/6] add path aliases --- tsconfig.json | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index 3cca8c9c..70c28d1f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,7 @@ { "compilerOptions": { "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -23,23 +19,15 @@ { "name": "next" } - ] - }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts" - ], - "exclude": [ - "node_modules" - ], - "paths": { - "@/*": [ - "./src/*" ], - "@/public/*": [ - "./public/*" - ] - } + "paths": { + "@/components/*": ["./src/components/*"], + "@/graphql/*": ["./src/graphql/*"], + "@/hooks/*": ["./src/hooks/*"], + "@/utils/*": ["./src/utils/*"], + "@/public/*": ["./public/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] } From efceff542b208b403eb4cbe545c63f105459432a Mon Sep 17 00:00:00 2001 From: Anze Demsar Date: Sat, 30 Sep 2023 10:03:29 +0200 Subject: [PATCH 2/6] diff votes dialog wip --- .../crag-route-list/crag-route.tsx | 14 +- .../crag-route/difficulty-votes.tsx | 120 ++++++++++++++++++ .../crag-route/route-grade.tsx | 34 +++++ .../server-actions/difficulty-votes-action.ts | 53 ++++++++ src/components/grade.tsx | 12 +- src/components/ui/dialog.tsx | 10 +- src/utils/text-helpers.ts | 13 ++ 7 files changed, 236 insertions(+), 20 deletions(-) create mode 100644 src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/difficulty-votes.tsx create mode 100644 src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/route-grade.tsx create mode 100644 src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/server-actions/difficulty-votes-action.ts diff --git a/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route.tsx b/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route.tsx index ca4447d8..8e23dfd6 100644 --- a/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route.tsx +++ b/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route.tsx @@ -11,6 +11,7 @@ import IconStarFull from "../../../../../../../components/ui/icons/star-full"; import Link from "../../../../../../../components/ui/link"; import { CragRoutesContext } from "../../crag-routes"; import { pluralizeNoun } from "../../../../../../../utils/text-helpers"; +import RouteGrade from "./crag-route/route-grade"; interface Props { crag: Crag; @@ -164,19 +165,6 @@ function CragRouteCompact({ crag, route, ascent }: Props) { ); } -interface RouteGradeProps { - route: Route; -} - -function RouteGrade({ route }: RouteGradeProps) { - return ( - <> - {route.isProject && "P"} - {route.difficulty && } - - ); -} - interface RouteStarRatingProps { route: Route; size?: IconSize; diff --git a/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/difficulty-votes.tsx b/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/difficulty-votes.tsx new file mode 100644 index 00000000..9c4e4bd5 --- /dev/null +++ b/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/difficulty-votes.tsx @@ -0,0 +1,120 @@ +import { useEffect, useState } from "react"; +import difficultyVotesAction from "./server-actions/difficulty-votes-action"; +import { DifficultyVote, Route } from "@/graphql/generated"; +import displayDate from "@/utils/display-date"; +import Grade, { diffToGrade } from "@/components/grade"; +import { pluralizeNoun } from "@/utils/text-helpers"; +import { gradingSystems } from "@/utils/grading-systems"; + +interface Props { + route: Route; +} + +function DifficultyVotes({ route }: Props) { + const [difficultyVotes, setDifficultyVotes] = useState([]); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + difficultyVotesAction(route.id) + .then((votes) => { + setDifficultyVotes(votes); + setLoading(false); + }) + .catch(() => { + setError("Napaka pri nalaganju glasov."); + }); + }, [route.id]); + + if (error) return
{error}
; + if (loading) return
Nalagam...
; + + const nrVotesPerDifficulty = difficultyVotes.reduce( + (acc, vote) => ({ + ...acc, + [vote.difficulty]: (acc[vote.difficulty] || 0) + 1, + }), + {} as Record + ); + const maxVotesPerDifficulty = Math.max( + ...Object.values(nrVotesPerDifficulty) + ); + + // const mainHighlightedDifficulty = route.difficulty && difficultyVotes[route.difficulty] ? + + const routeGradeDifficulty = route.difficulty + ? diffToGrade(route.difficulty, "french", false).difficulty + : null; + + return ( + <> + + + {Object.entries(nrVotesPerDifficulty).map(([difficulty, nrVotes]) => ( + + + + + + ))} + +
+ + + + + + {nrVotes !== maxVotesPerDifficulty && + pluralizeNoun("glas", nrVotes)} + + + + {nrVotes === maxVotesPerDifficulty && + pluralizeNoun("glas", nrVotes)} +
+ + + {difficultyVotes.map((vote) => ( + + + + + + ))} + +
+ + + {vote.isBase ? "(bazna ocena)" : vote.user?.fullName} + {displayDate(vote.created)}
+ + ); +} + +export default DifficultyVotes; diff --git a/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/route-grade.tsx b/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/route-grade.tsx new file mode 100644 index 00000000..2bd46fa8 --- /dev/null +++ b/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/route-grade.tsx @@ -0,0 +1,34 @@ +import Grade from "../../../../../../../../components/grade"; +import Dialog, { + DialogSize, +} from "../../../../../../../../components/ui/dialog"; +import { Route } from "../../../../../../../../graphql/generated"; +import DifficultyVotes from "./difficulty-votes"; + +interface RouteGradeProps { + route: Route; +} + +function RouteGrade({ route }: RouteGradeProps) { + const handleOpenRoutePage = () => {}; + const handleCloseDialog = () => {}; + + return ( + + {route.isProject && "P"} + {route.difficulty && } + + } + dialogSize={DialogSize.hug} + title="Glasovi uporabnikov" + confirm={{ label: "Več", callback: handleOpenRoutePage }} + cancel={{ label: "Zapri", callback: handleCloseDialog }} + > + + + ); +} + +export default RouteGrade; diff --git a/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/server-actions/difficulty-votes-action.ts b/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/server-actions/difficulty-votes-action.ts new file mode 100644 index 00000000..28e9ec22 --- /dev/null +++ b/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/server-actions/difficulty-votes-action.ts @@ -0,0 +1,53 @@ +"use server"; + +import { gql } from "urql/core"; +import { + DifficultyVote, + RouteDifficultyVotesDocument, +} from "@/graphql/generated"; +import urqlServer from "@/graphql/urql-server"; + +async function difficultyVotesAction( + routeId: string +): Promise { + const result = await urqlServer().query(RouteDifficultyVotesDocument, { + routeId, + }); + + if (result.error) { + return Promise.reject(result.error); + } + + return result.data.route.difficultyVotes; +} + +export default difficultyVotesAction; + +gql` + query RouteDifficultyVotes($routeId: String!) { + route(id: $routeId) { + id + slug + difficulty + defaultGradingSystem { + id + } + name + length + difficultyVotes { + user { + id + fullName + firstname + lastname + } + id + difficulty + created + updated + isBase + includedInCalculation + } + } + } +`; diff --git a/src/components/grade.tsx b/src/components/grade.tsx index fb002793..b6c462e1 100644 --- a/src/components/grade.tsx +++ b/src/components/grade.tsx @@ -11,6 +11,7 @@ type Props = { type GradeDisplay = { name: string; + difficulty?: number; modifier: -1 | 0 | 1; }; @@ -22,7 +23,6 @@ function Grade({ disabled = false, }: Props) { const gradeDisplay = diffToGrade( - gradingSystems as GradingSystem[], difficulty, gradingSystemId, displayIntermediate @@ -30,8 +30,7 @@ function Grade({ return <>{gradeDisplay.name}; } -function diffToGrade( - gradingSystems: GradingSystem[], +export function diffToGrade( difficulty: number, gradingSystemId: string, legacy: boolean = false @@ -62,11 +61,13 @@ function diffToGrade( if (difficulty <= grades[0].difficulty) { return { name: grades[0].name, + difficulty: grades[0].difficulty, modifier: 0, }; } else if (difficulty >= grades[grades.length - 1].difficulty) { return { name: grades[grades.length - 1].name, + difficulty: grades[grades.length - 1].difficulty, modifier: 0, }; } @@ -91,11 +92,13 @@ function diffToGrade( ) { return { name: curr.name, + difficulty: curr.difficulty, modifier: 0, }; } else { return { name: curr.name, + difficulty: curr.difficulty, modifier: -1, }; } @@ -108,17 +111,20 @@ function diffToGrade( ) { return { name: curr.name, + difficulty: curr.difficulty, modifier: 0, }; } else { return { name: curr.name, + difficulty: curr.difficulty, modifier: +1, }; } } else { return { name: curr.name, + difficulty: curr.difficulty, modifier: 0, }; } diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx index 8f05e90c..a71f466d 100644 --- a/src/components/ui/dialog.tsx +++ b/src/components/ui/dialog.tsx @@ -71,12 +71,14 @@ function Dialog({
{title} - - {children} - + {isOpen && ( + + {children} + + )}
+ } + dialogSize={DialogSize.hug} + title="Glasovi uporabnikov" + confirm={{ label: "Več", callback: handleOpenRoutePage }} + cancel={{ label: "Zapri", callback: handleCloseDialog }} + > + + + ); +} + +export default RouteGrade; diff --git a/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/server-actions/difficulty-votes-action.ts b/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/server-actions/difficulty-votes-action.ts new file mode 100644 index 00000000..28e9ec22 --- /dev/null +++ b/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/server-actions/difficulty-votes-action.ts @@ -0,0 +1,53 @@ +"use server"; + +import { gql } from "urql/core"; +import { + DifficultyVote, + RouteDifficultyVotesDocument, +} from "@/graphql/generated"; +import urqlServer from "@/graphql/urql-server"; + +async function difficultyVotesAction( + routeId: string +): Promise { + const result = await urqlServer().query(RouteDifficultyVotesDocument, { + routeId, + }); + + if (result.error) { + return Promise.reject(result.error); + } + + return result.data.route.difficultyVotes; +} + +export default difficultyVotesAction; + +gql` + query RouteDifficultyVotes($routeId: String!) { + route(id: $routeId) { + id + slug + difficulty + defaultGradingSystem { + id + } + name + length + difficultyVotes { + user { + id + fullName + firstname + lastname + } + id + difficulty + created + updated + isBase + includedInCalculation + } + } + } +`; diff --git a/src/components/grade.tsx b/src/components/grade.tsx index fb002793..b6c462e1 100644 --- a/src/components/grade.tsx +++ b/src/components/grade.tsx @@ -11,6 +11,7 @@ type Props = { type GradeDisplay = { name: string; + difficulty?: number; modifier: -1 | 0 | 1; }; @@ -22,7 +23,6 @@ function Grade({ disabled = false, }: Props) { const gradeDisplay = diffToGrade( - gradingSystems as GradingSystem[], difficulty, gradingSystemId, displayIntermediate @@ -30,8 +30,7 @@ function Grade({ return <>{gradeDisplay.name}; } -function diffToGrade( - gradingSystems: GradingSystem[], +export function diffToGrade( difficulty: number, gradingSystemId: string, legacy: boolean = false @@ -62,11 +61,13 @@ function diffToGrade( if (difficulty <= grades[0].difficulty) { return { name: grades[0].name, + difficulty: grades[0].difficulty, modifier: 0, }; } else if (difficulty >= grades[grades.length - 1].difficulty) { return { name: grades[grades.length - 1].name, + difficulty: grades[grades.length - 1].difficulty, modifier: 0, }; } @@ -91,11 +92,13 @@ function diffToGrade( ) { return { name: curr.name, + difficulty: curr.difficulty, modifier: 0, }; } else { return { name: curr.name, + difficulty: curr.difficulty, modifier: -1, }; } @@ -108,17 +111,20 @@ function diffToGrade( ) { return { name: curr.name, + difficulty: curr.difficulty, modifier: 0, }; } else { return { name: curr.name, + difficulty: curr.difficulty, modifier: +1, }; } } else { return { name: curr.name, + difficulty: curr.difficulty, modifier: 0, }; } diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx index 8f05e90c..a71f466d 100644 --- a/src/components/ui/dialog.tsx +++ b/src/components/ui/dialog.tsx @@ -71,12 +71,14 @@ function Dialog({
{title} - - {children} - + {isOpen && ( + + {children} + + )}
+ } + dialogSize={DialogSize.hug} + title="Glasovi uporabnikov" + confirm={{ label: "Več", callback: handleOpenRoutePage }} + cancel={{ label: "Zapri", callback: handleCloseDialog }} + > + + + ); +} + +export default RouteGrade; diff --git a/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/server-actions/difficulty-votes-action.ts b/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/server-actions/difficulty-votes-action.ts new file mode 100644 index 00000000..28e9ec22 --- /dev/null +++ b/src/app/[lang]/crag/[cragSlug]/components/crag-routes/crag-route-list/crag-route/server-actions/difficulty-votes-action.ts @@ -0,0 +1,53 @@ +"use server"; + +import { gql } from "urql/core"; +import { + DifficultyVote, + RouteDifficultyVotesDocument, +} from "@/graphql/generated"; +import urqlServer from "@/graphql/urql-server"; + +async function difficultyVotesAction( + routeId: string +): Promise { + const result = await urqlServer().query(RouteDifficultyVotesDocument, { + routeId, + }); + + if (result.error) { + return Promise.reject(result.error); + } + + return result.data.route.difficultyVotes; +} + +export default difficultyVotesAction; + +gql` + query RouteDifficultyVotes($routeId: String!) { + route(id: $routeId) { + id + slug + difficulty + defaultGradingSystem { + id + } + name + length + difficultyVotes { + user { + id + fullName + firstname + lastname + } + id + difficulty + created + updated + isBase + includedInCalculation + } + } + } +`; diff --git a/src/components/grade.tsx b/src/components/grade.tsx index fb002793..b6c462e1 100644 --- a/src/components/grade.tsx +++ b/src/components/grade.tsx @@ -11,6 +11,7 @@ type Props = { type GradeDisplay = { name: string; + difficulty?: number; modifier: -1 | 0 | 1; }; @@ -22,7 +23,6 @@ function Grade({ disabled = false, }: Props) { const gradeDisplay = diffToGrade( - gradingSystems as GradingSystem[], difficulty, gradingSystemId, displayIntermediate @@ -30,8 +30,7 @@ function Grade({ return <>{gradeDisplay.name}; } -function diffToGrade( - gradingSystems: GradingSystem[], +export function diffToGrade( difficulty: number, gradingSystemId: string, legacy: boolean = false @@ -62,11 +61,13 @@ function diffToGrade( if (difficulty <= grades[0].difficulty) { return { name: grades[0].name, + difficulty: grades[0].difficulty, modifier: 0, }; } else if (difficulty >= grades[grades.length - 1].difficulty) { return { name: grades[grades.length - 1].name, + difficulty: grades[grades.length - 1].difficulty, modifier: 0, }; } @@ -91,11 +92,13 @@ function diffToGrade( ) { return { name: curr.name, + difficulty: curr.difficulty, modifier: 0, }; } else { return { name: curr.name, + difficulty: curr.difficulty, modifier: -1, }; } @@ -108,17 +111,20 @@ function diffToGrade( ) { return { name: curr.name, + difficulty: curr.difficulty, modifier: 0, }; } else { return { name: curr.name, + difficulty: curr.difficulty, modifier: +1, }; } } else { return { name: curr.name, + difficulty: curr.difficulty, modifier: 0, }; } diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx index 8f05e90c..a71f466d 100644 --- a/src/components/ui/dialog.tsx +++ b/src/components/ui/dialog.tsx @@ -71,12 +71,14 @@ function Dialog({
{title} - - {children} - + {isOpen && ( + + {children} + + )}