From cefeccaf9fe01ca2a4dab4205f43946614ad0892 Mon Sep 17 00:00:00 2001 From: Prashant Kumar Date: Tue, 8 Oct 2024 09:30:13 +0530 Subject: [PATCH 1/2] added functionality to navigate through videos by prev and next video button --- pnpm-lock.yaml | 357 +++++++++++++++++- .../courses/[courseId]/[...moduleId]/page.tsx | 22 +- src/app/courses/[courseId]/page.tsx | 2 + src/app/layout.tsx | 3 + src/components/ContentCard.tsx | 1 + src/components/CourseView.tsx | 3 + src/components/VideoPlayer2.tsx | 76 ++-- src/components/VideoPlayerSegment.tsx | 12 + src/components/admin/ContentRenderer.tsx | 9 +- .../admin/ContentRendererClient.tsx | 52 +-- src/db/course.ts | 43 ++- tsconfig.json | 27 +- 12 files changed, 525 insertions(+), 82 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a04131228..6a39d1ca3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,7 +33,7 @@ importers: specifier: ^1.0.4 version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-dialog': - specifier: ^1.0.5 + specifier: ^1.1.1 version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-dropdown-menu': specifier: ^2.0.6 @@ -67,7 +67,7 @@ importers: version: 1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@tabler/icons-react': specifier: ^3.14.0 - version: 3.17.0(react@18.3.1) + version: 3.14.0(react@18.3.1) '@types/bcrypt': specifier: ^5.0.2 version: 5.0.2 @@ -92,6 +92,9 @@ importers: clsx: specifier: ^2.1.0 version: 2.1.1 + cmdk: + specifier: 1.0.0 + version: 1.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) date-fns: specifier: ^3.6.0 version: 3.6.0 @@ -1601,6 +1604,9 @@ packages: '@radix-ui/number@1.1.0': resolution: {integrity: sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==} + '@radix-ui/primitive@1.0.1': + resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} + '@radix-ui/primitive@1.1.0': resolution: {integrity: sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==} @@ -1669,6 +1675,15 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-compose-refs@1.0.1': + resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-compose-refs@1.1.0': resolution: {integrity: sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==} peerDependencies: @@ -1678,6 +1693,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-context@1.0.1': + resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-context@1.1.0': resolution: {integrity: sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==} peerDependencies: @@ -1696,6 +1720,19 @@ packages: '@types/react': optional: true + '@radix-ui/react-dialog@1.0.5': + resolution: {integrity: sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-dialog@1.1.1': resolution: {integrity: sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==} peerDependencies: @@ -1718,6 +1755,19 @@ packages: '@types/react': optional: true + '@radix-ui/react-dismissable-layer@1.0.5': + resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-dismissable-layer@1.1.0': resolution: {integrity: sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==} peerDependencies: @@ -1744,6 +1794,15 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-focus-guards@1.0.1': + resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-focus-guards@1.1.0': resolution: {integrity: sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==} peerDependencies: @@ -1753,6 +1812,19 @@ packages: '@types/react': optional: true + '@radix-ui/react-focus-scope@1.0.4': + resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-focus-scope@1.1.0': resolution: {integrity: sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==} peerDependencies: @@ -1766,6 +1838,15 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-id@1.0.1': + resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-id@1.1.0': resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} peerDependencies: @@ -1840,6 +1921,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-portal@1.0.4': + resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-portal@1.1.1': resolution: {integrity: sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==} peerDependencies: @@ -1853,6 +1947,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-presence@1.0.1': + resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-presence@1.1.0': resolution: {integrity: sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==} peerDependencies: @@ -1879,6 +1986,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-primitive@1.0.3': + resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-primitive@2.0.0': resolution: {integrity: sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==} peerDependencies: @@ -1944,6 +2064,15 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-slot@1.0.2': + resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-slot@1.1.0': resolution: {integrity: sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==} peerDependencies: @@ -1979,6 +2108,15 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-use-callback-ref@1.0.1': + resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-callback-ref@1.1.0': resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} peerDependencies: @@ -1988,6 +2126,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-controllable-state@1.0.1': + resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-controllable-state@1.1.0': resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} peerDependencies: @@ -1997,6 +2144,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-escape-keydown@1.0.3': + resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-escape-keydown@1.1.0': resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==} peerDependencies: @@ -2006,6 +2162,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-use-layout-effect@1.0.1': + resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-use-layout-effect@1.1.0': resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} peerDependencies: @@ -3304,6 +3469,12 @@ packages: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} + cmdk@1.0.0: + resolution: {integrity: sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -6016,6 +6187,16 @@ packages: '@types/react': optional: true + react-remove-scroll@2.5.5: + resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + react-remove-scroll@2.5.7: resolution: {integrity: sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==} engines: {node: '>=10'} @@ -8699,6 +8880,10 @@ snapshots: '@radix-ui/number@1.1.0': {} + '@radix-ui/primitive@1.0.1': + dependencies: + '@babel/runtime': 7.25.0 + '@radix-ui/primitive@1.1.0': {} '@radix-ui/react-accordion@1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': @@ -8767,12 +8952,26 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 + '@radix-ui/react-compose-refs@1.0.1(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.25.0 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.3 + '@radix-ui/react-compose-refs@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: react: 18.3.1 optionalDependencies: '@types/react': 18.3.3 + '@radix-ui/react-context@1.0.1(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.25.0 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.3 + '@radix-ui/react-context@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: react: 18.3.1 @@ -8785,6 +8984,29 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 + '@radix-ui/react-dialog@1.0.5(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.25.0 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-context': 1.0.1(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-id': 1.0.1(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.0.2(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.3.3)(react@18.3.1) + aria-hidden: 1.2.4 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-remove-scroll: 2.5.5(@types/react@18.3.3)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 + '@radix-ui/react-dialog@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 @@ -8813,6 +9035,20 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 + '@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.25.0 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.3.3)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 + '@radix-ui/react-dismissable-layer@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 @@ -8841,12 +9077,31 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 + '@radix-ui/react-focus-guards@1.0.1(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.25.0 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.3 + '@radix-ui/react-focus-guards@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: react: 18.3.1 optionalDependencies: '@types/react': 18.3.3 + '@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.25.0 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.3)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 + '@radix-ui/react-focus-scope@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -8858,6 +9113,14 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 + '@radix-ui/react-id@1.0.1(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.25.0 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.3)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.3 + '@radix-ui/react-id@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -8963,6 +9226,16 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 + '@radix-ui/react-portal@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.25.0 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 + '@radix-ui/react-portal@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -8973,6 +9246,17 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 + '@radix-ui/react-presence@1.0.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.25.0 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.3)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 + '@radix-ui/react-presence@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -8993,6 +9277,16 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 + '@radix-ui/react-primitive@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.25.0 + '@radix-ui/react-slot': 1.0.2(@types/react@18.3.3)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 + '@radix-ui/react-primitive@2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-slot': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -9063,6 +9357,14 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 + '@radix-ui/react-slot@1.0.2(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.25.0 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.3)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.3 + '@radix-ui/react-slot@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -9105,12 +9407,27 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 + '@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.25.0 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.3 + '@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: react: 18.3.1 optionalDependencies: '@types/react': 18.3.3 + '@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.25.0 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.3)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.3 + '@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -9118,6 +9435,14 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 + '@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.25.0 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.3)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.3 + '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -9125,6 +9450,13 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 + '@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.25.0 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.3 + '@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: react: 18.3.1 @@ -10793,6 +11125,16 @@ snapshots: cluster-key-slot@1.1.2: {} + cmdk@1.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@radix-ui/react-dialog': 1.0.5(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + color-convert@1.9.3: dependencies: color-name: 1.1.3 @@ -13913,6 +14255,17 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 + react-remove-scroll@2.5.5(@types/react@18.3.3)(react@18.3.1): + dependencies: + react: 18.3.1 + react-remove-scroll-bar: 2.3.6(@types/react@18.3.3)(react@18.3.1) + react-style-singleton: 2.2.1(@types/react@18.3.3)(react@18.3.1) + tslib: 2.6.3 + use-callback-ref: 1.3.2(@types/react@18.3.3)(react@18.3.1) + use-sidecar: 1.1.2(@types/react@18.3.3)(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.3 + react-remove-scroll@2.5.7(@types/react@18.3.3)(react@18.3.1): dependencies: react: 18.3.1 diff --git a/src/app/courses/[courseId]/[...moduleId]/page.tsx b/src/app/courses/[courseId]/[...moduleId]/page.tsx index 4e057393d..1a6c83ddc 100644 --- a/src/app/courses/[courseId]/[...moduleId]/page.tsx +++ b/src/app/courses/[courseId]/[...moduleId]/page.tsx @@ -1,6 +1,6 @@ import { QueryParams } from '@/actions/types'; import { CourseView } from '@/components/CourseView'; -import { getCourse, getFullCourseContent } from '@/db/course'; +import { getCourse, getCourseAllVideos, getFullCourseContent } from '@/db/course'; import findContentById from '@/lib/find-content-by-id'; export default async function Course({ @@ -20,13 +20,29 @@ export default async function Course({ fullCourseContent, rest.map((x) => parseInt(x, 10)), ); - const nextContent = null; //await getNextVideo(Number(rest[rest.length - 1])) + + const CurrentCourseAllVideos = await getCourseAllVideos(Number(courseId)); + const nextContent = CurrentCourseAllVideos.find((video: any) => { + return video.id > Number(rest[rest.length - 1]); + }); + const prevContent = (() => { + for (let i = CurrentCourseAllVideos.length - 1; i >= 0; i--) { + if (CurrentCourseAllVideos[i].id < Number(rest[rest.length - 1])) { + return CurrentCourseAllVideos[i]; + } + } + return null; + })(); + + const nextContentUrl = (nextContent ? `/courses/${courseId}/${nextContent.parentId}/${nextContent.id}` : null); + const prevContentUrl = (prevContent ? `/courses/${courseId}/${prevContent.parentId}/${prevContent.id}` : null); return ( + + + { @@ -56,6 +58,7 @@ export const CourseView = ({ {!courseContent?.folder && contentType === 'video' ? ( void; + onNextVideoClick: () => void; + onPrevVideoClick: () => void; + isnextContentAvailable: boolean; + ispreviousContentAvailable: boolean; } const PLAYBACK_RATES: number[] = [0.5, 1, 1.25, 1.5, 1.75, 2]; @@ -37,6 +40,10 @@ export const VideoPlayer: FunctionComponent = ({ onReady, subtitles, onVideoEnd, + onNextVideoClick, + onPrevVideoClick, + isnextContentAvailable, + ispreviousContentAvailable, }) => { const videoRef = useRef(null); const playerRef = useRef(null); @@ -64,34 +71,29 @@ export const VideoPlayer: FunctionComponent = ({ } }; - const PipButton = () => ( - - ); - const createPipButton = (player: Player) => { - const pipButtonContainer = (player as any).controlBar.addChild('button', { - clickHandler: (event: any) => { - event.preventDefault(); - event.stopPropagation(); - togglePictureInPicture(); - }, - }); + const pipButtonContainer = (player as any).controlBar.addChild('button'); const root = createRoot(pipButtonContainer.el()); - root.render(); + root.render(picture_in_picture_alt); return pipButtonContainer; }; + const createNextVideoButton = (player: Player) => { + const NextButtonContainer = (player as any).controlBar.addChild('button'); + const root = createRoot(NextButtonContainer.el()); + root.render(skip_next); + return NextButtonContainer; + }; + + const createPrevVideoButton = (player: Player) => { + const PrevButtonContainer = (player as any).controlBar.addChild('button'); + const root = createRoot(PrevButtonContainer.el()); + root.render(skip_previous); + return PrevButtonContainer; + }; + useEffect(() => { const t = searchParams.get('timestamp'); if (contentId && player && !t) { @@ -318,6 +320,7 @@ export const VideoPlayer: FunctionComponent = ({ document.removeEventListener('keydown', handleKeyPress); }; }, [player]); + useEffect(() => { if (!player) { return; @@ -396,11 +399,32 @@ export const VideoPlayer: FunctionComponent = ({ back: 15, }); + const controlBar = player.getChild('controlBar'); + if (isnextContentAvailable) { + const nextVideoButton = createNextVideoButton(player); + const skipBackwardBtn = controlBar.getChild('skipBackward'); + controlBar.el().insertBefore(nextVideoButton.el(), skipBackwardBtn.el()); + nextVideoButton.on('click', (e: any) => { + e.preventDefault(); + e.stopPropagation(); + onNextVideoClick(); + }); + } + if (ispreviousContentAvailable) { + const prevVideoButton = createPrevVideoButton(player); + const playButton = controlBar.getChild('playToggle'); + controlBar.el().insertBefore(prevVideoButton.el(), playButton.el()); + prevVideoButton.on('click', (e: any) => { + e.preventDefault(); + e.stopPropagation(); + onPrevVideoClick(); + }); + } + player.qualitySelector = setQuality; const qualitySelector = player.controlBar.addChild( 'QualitySelectorControllBar', ); - const controlBar = player.getChild('controlBar'); const fullscreenToggle = controlBar.getChild('fullscreenToggle'); controlBar @@ -410,6 +434,12 @@ export const VideoPlayer: FunctionComponent = ({ const pipButton = createPipButton(player); controlBar.el().insertBefore(pipButton.el(), fullscreenToggle.el()); + pipButton.on('click', (e:any) => { + e.preventDefault(); + e.stopPropagation(); + togglePictureInPicture(); + }); + setPlayer(player); if (options.isComposite) { player.spriteThumbnails({ diff --git a/src/components/VideoPlayerSegment.tsx b/src/components/VideoPlayerSegment.tsx index 5c5a9b3fa..b74273117 100644 --- a/src/components/VideoPlayerSegment.tsx +++ b/src/components/VideoPlayerSegment.tsx @@ -25,6 +25,10 @@ interface VideoProps { videoJsOptions: any; contentId: number; onVideoEnd: () => void; + onNextVideoClick: () => void; + onPrevVideoClick: () => void; + isnextContentAvailable: boolean; + ispreviousContentAvailable: boolean; } export const VideoPlayerSegment: FunctionComponent = ({ @@ -34,6 +38,10 @@ export const VideoPlayerSegment: FunctionComponent = ({ segments, videoJsOptions, onVideoEnd, + onNextVideoClick, + onPrevVideoClick, + isnextContentAvailable, + ispreviousContentAvailable, }) => { const playerRef = useRef(null); @@ -103,6 +111,10 @@ export const VideoPlayerSegment: FunctionComponent = ({ options={videoJsOptions} onVideoEnd={onVideoEnd} onReady={handlePlayerReady} + onNextVideoClick={onNextVideoClick} + onPrevVideoClick={onPrevVideoClick} + isnextContentAvailable={isnextContentAvailable} + ispreviousContentAvailable={ispreviousContentAvailable} /> diff --git a/src/components/admin/ContentRenderer.tsx b/src/components/admin/ContentRenderer.tsx index e29bc143a..8d95b8f41 100644 --- a/src/components/admin/ContentRenderer.tsx +++ b/src/components/admin/ContentRenderer.tsx @@ -126,12 +126,10 @@ export const getMetadata = async (contentId: number) => { export const ContentRenderer = async ({ content, nextContent, + prevContent, }: { - nextContent: { - id: number; - type: string; - title: string; - } | null; + nextContent: string | null; + prevContent: string | null; content: { type: 'video'; id: number; @@ -148,6 +146,7 @@ export const ContentRenderer = async ({
diff --git a/src/components/admin/ContentRendererClient.tsx b/src/components/admin/ContentRendererClient.tsx index 018aecc71..7bf2047d1 100644 --- a/src/components/admin/ContentRendererClient.tsx +++ b/src/components/admin/ContentRendererClient.tsx @@ -11,12 +11,10 @@ export const ContentRendererClient = ({ metadata, content, nextContent, + prevContent, }: { - nextContent: { - id: number; - type: string; - title: string; - } | null; + nextContent: string | null; + prevContent: string | null; metadata: any; content: { type: 'video'; @@ -71,6 +69,29 @@ export const ContentRendererClient = ({ setShowChapters((prev) => !prev); }; + const handleOnNextVideoClick = () => { + if (!nextContent) { + router.push('/'); + return; + } + router.push(nextContent); + }; + + const handleOnPrevVideoClick = () => { + if (!prevContent) { + router.push('/'); + return; + } + router.push(prevContent); + }; + + const handleOnVideoEnd = () => { + if (!nextContent) { + return null; + } + router.push(nextContent); + }; + return (
@@ -98,7 +119,11 @@ export const ContentRendererClient = ({ responsive: true, sources: [source], }} - onVideoEnd={() => {}} + onVideoEnd={handleOnVideoEnd} + onNextVideoClick={handleOnNextVideoClick} + onPrevVideoClick={handleOnPrevVideoClick} + isnextContentAvailable={nextContent?true:false} + ispreviousContentAvailable={prevContent?true:false} />
@@ -139,21 +164,6 @@ export const ContentRendererClient = ({ /> )}
- {nextContent ? ( - - ) : null}
); diff --git a/src/db/course.ts b/src/db/course.ts index 6183cf084..64a8868e2 100644 --- a/src/db/course.ts +++ b/src/db/course.ts @@ -133,37 +133,36 @@ export async function getCourse(courseId: number) { return courses; } -export const getNextVideo = async (currentVideoId: number) => { - if (!currentVideoId) { +export const getCourseAllVideos = async (currentCourse: number) => { + if (!currentCourse) { return null; } - const value = await cache.get('getNextVideo', [currentVideoId.toString()]); + const value = await cache.get('getCourseAllVideos', [String(currentCourse)]); if (value) { return value; } - const currentContent = await db.content.findFirst({ - where: { - id: currentVideoId, - }, - }); - const latestContent = await db.content.findFirst({ - orderBy: [ - { - id: 'asc', - }, - ], + const allVideos = await db.content.findMany({ + orderBy: { + id: 'asc', + }, where: { - parentId: { - equals: currentContent?.parentId, - }, - id: { - gt: currentVideoId, + parent: { + courses: { + some: { + courseId: currentCourse + } + }, }, - }, + type: "video", + } }); - cache.set('getNextVideo', [currentVideoId.toString()], latestContent); - return latestContent; + + if (!allVideos || allVideos.length<1) { + return null; + } + cache.set('getCourseAllVideos', [String(currentCourse)], allVideos); + return allVideos; }; async function getAllContent(): Promise< diff --git a/tsconfig.json b/tsconfig.json index 88f05644b..adf349623 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,11 @@ "compilerOptions": { "baseUrl": ".", "target": "es5", - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -12,7 +16,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "react-jsx", + "jsx": "preserve", "incremental": true, "plugins": [ { @@ -20,10 +24,21 @@ } ], "paths": { - "@/*": ["./src/*"], - "@public/*": ["./public/*"] + "@/*": [ + "./src/*" + ], + "@public/*": [ + "./public/*" + ] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts" + ], + "exclude": [ + "node_modules" + ] } From a99f66193a216511e625db13f2e527fe1e8c052e Mon Sep 17 00:00:00 2001 From: Prashant Kumar Date: Wed, 23 Oct 2024 10:34:08 +0530 Subject: [PATCH 2/2] fixed al the errors realted to pip button --- src/app/layout.tsx | 3 --- src/components/ContentCard.tsx | 1 - src/components/VideoPlayer2.tsx | 24 +++++++++++++++++++++--- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 9ab1f4a7a..976e9c458 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -25,9 +25,6 @@ export const metadata: Metadata = siteConfig; export default function RootLayout({ children }: { children: ReactNode }) { return ( - - - = ({ const pipButtonContainer = (player as any).controlBar.addChild('button'); const root = createRoot(pipButtonContainer.el()); - root.render(picture_in_picture_alt); + root.render( +
+ +
+ ); return pipButtonContainer; }; @@ -83,14 +88,22 @@ export const VideoPlayer: FunctionComponent = ({ const createNextVideoButton = (player: Player) => { const NextButtonContainer = (player as any).controlBar.addChild('button'); const root = createRoot(NextButtonContainer.el()); - root.render(skip_next); + root.render( +
+ +
+ ); return NextButtonContainer; }; const createPrevVideoButton = (player: Player) => { const PrevButtonContainer = (player as any).controlBar.addChild('button'); const root = createRoot(PrevButtonContainer.el()); - root.render(skip_previous); + root.render( +
+ +
+ ); return PrevButtonContainer; }; @@ -433,6 +446,11 @@ export const VideoPlayer: FunctionComponent = ({ const pipButton = createPipButton(player); controlBar.el().insertBefore(pipButton.el(), fullscreenToggle.el()); + // pipButton.on('click', (e: any) => { + // e.preventDefault(); + // e.stopPropagation(); + // togglePictureInPicture(); + // }); pipButton.on('click', (e:any) => { e.preventDefault();