Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions examples/music-licensing-challenge-nextjs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files (can opt-in for committing if needed)
.env*

# vercel
.vercel

# typescript
*.tsbuildinfo
4 changes: 4 additions & 0 deletions examples/music-licensing-challenge-nextjs/.husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

pnpm run lint-staged
4 changes: 4 additions & 0 deletions examples/music-licensing-challenge-nextjs/.husky/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/sh
. "$(dirname "$0")/_/husky.sh"

npm run type-check
92 changes: 92 additions & 0 deletions examples/music-licensing-challenge-nextjs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Music Licensing Challenge Frontend


## Features
- Movie, scene, track, and song management UI
- License status management for songs
- Real-time updates for license status via GraphQL subscriptions
- Authentication (login/register)
- TypeScript, TailwindCSS, and Apollo Client integration
- Linting and formatting with BiomeJs

## Tech Stack
- [Next.js 15 (App Router)](https://nextjs.org/)
- [React 19](https://react.dev/)
- [Apollo Client 3](https://www.apollographql.com/docs/react/)
- [GraphQL](https://graphql.org/)
- [TailwindCSS 4](https://tailwindcss.com/)
- [TypeScript](https://www.typescriptlang.org/)
- [Biome](https://biomejs.dev/) (linting/formatting)

## Getting Started

1. **Install dependencies:**
```bash
pnpm install
# or
npm install
# or
yarn install
```

2. **Set up environment variables:**
- Create a `.env.local` file with:
```env
NEXT_PUBLIC_GRAPHQL_URL=your-graphql-http-endpoint
NEXT_PUBLIC_WS_URL=your-graphql-ws-endpoint
```

3. **Run the development server:**
```bash
pnpm dev
# or
npm run dev
# or
yarn dev
```
Open [http://localhost:3000](http://localhost:3000) in your browser.

## Project Structure
- `src/app/` — App Router pages, layouts, and routes (including movies, scenes, auth)
- `src/components/` — UI components (SceneList, MovieCard, Navbar, etc.)
- `src/lib/graphql/` — Apollo Client setup, queries, mutations, subscriptions
- `src/hooks/` — Custom React hooks (e.g., `useSongWithLiveStatus`)
- `src/types/` — TypeScript type definitions
- `src/styles/` — Global and Tailwind styles

## GraphQL Usage
- **Apollo Client** is set up in `src/lib/graphql/client.ts` with HTTP and WebSocket links for queries/mutations and subscriptions.
- **Queries:**
- Example: `GET_SONG_BY_ID`, `GET_SCENES`, `GET_MOVIES` in `src/lib/graphql/queries/`
- **Mutations:**
- Example: `UPDATE_SONG_LICENSE_STATUS` in `src/lib/graphql/mutations/songs.ts`
- **Subscriptions:**
- Example: `LICENSE_STATUS_UPDATED` in `src/lib/graphql/subscriptions/license-status.ts`
- **Custom Hooks:**
- `useSongWithLiveStatus(song)` — Combines query and subscription for live song status

## Linting & Formatting
- Run `pnpm lint` or `pnpm format` to lint/format code with Biome.
- Type-check with `pnpm type-check`.

## TypeScript
- Full TypeScript support with strict settings (`tsconfig.json`)
- Types in `src/types/`

## Styling
- TailwindCSS is used for all styling. See `src/styles/globals.css`.

## Contributing
Pull requests are welcome! Please lint, format, and type-check your code before submitting.

---

For more, see the source code and comments throughout the project.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

54 changes: 54 additions & 0 deletions examples/music-licensing-challenge-nextjs/biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"vcs": {
"enabled": false,
"clientKind": "git",
"useIgnoreFile": false
},
"files": {
"ignoreUnknown": false,
"ignore": [".next"],
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Expand ignore patterns to include more build and dependency directories

The current ignore patterns only exclude the .next directory, but other common directories should also be excluded.

 	"files": {
 		"ignoreUnknown": false,
-		"ignore": [".next"],
+		"ignore": [
+			".next",
+			"node_modules",
+			"dist",
+			"build",
+			"public",
+			".git",
+			".husky"
+		],
 		"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx", "**/*.css"]
 	},
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"ignore": [".next"],
"files": {
"ignoreUnknown": false,
"ignore": [
".next",
"node_modules",
"dist",
"build",
"public",
".git",
".husky"
],
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx", "**/*.css"]
},

"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx", "**/*.css"]
},
"formatter": {
"enabled": true,
"indentStyle": "tab"
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": {
"noArrayIndexKey": "warn"
},
"a11y": {
"useAltText": "warn",
"useValidAnchor": "warn",
"noSvgWithoutTitle": "warn"
},
"complexity": {
"noExtraBooleanCast": "warn"
},
"correctness": {
"noUnusedVariables": "error",
"noUnusedImports": "error"
}
}
},
"javascript": {
"formatter": {
"arrowParentheses": "always",
"bracketSameLine": false,
"bracketSpacing": true,
"semicolons": "always",
"trailingCommas": "all",
"jsxQuoteStyle": "double",
"quoteProperties": "asNeeded",
"lineWidth": 80,
"indentWidth": 2
Comment on lines +50 to +51
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure indentation width is consistent with formatter settings

The indentation width is set to 2 spaces, but the formatter is configured to use tabs. This inconsistency can lead to formatting issues.

 			"jsxQuoteStyle": "double",
 			"quoteProperties": "asNeeded",
 			"lineWidth": 80,
-			"indentWidth": 2
+			"indentStyle": "tab",
+			"indentWidth": 2 // Only applies when indentStyle is "space"

Committable suggestion skipped: line range outside the PR's diff.

}
}
}
7 changes: 7 additions & 0 deletions examples/music-licensing-challenge-nextjs/env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
NEXT_PUBLIC_API_BASE_URL=
NEXT_PUBLIC_AUTH_SECRET=
NEXT_PUBLIC_USER_EXAMPLE=
NEXT_PUBLIC_PASSWORD_EXAMPLE=
NEXT_PUBLIC_WS_URL=
NEXT_PUBLIC_GRAPHQL_URL=
NEXTAUTH_URL=
5 changes: 5 additions & 0 deletions examples/music-licensing-challenge-nextjs/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
17 changes: 17 additions & 0 deletions examples/music-licensing-challenge-nextjs/next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "**",
},
],
},
Comment on lines +4 to +11
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Security concern with image remote patterns configuration

The current configuration allows loading images from any HTTPS hostname, which is overly permissive and could pose security risks like content injection or tracking vulnerabilities.

Consider restricting the remote patterns to only specific domains that you actually need:

images: {
	remotePatterns: [
		{
			protocol: "https",
-			hostname: "**",
+			hostname: "trusted-image-domain.com",
		},
+		// Add other specific domains as needed
	],
},

If you need multiple domains, add them as separate entries with specific hostnames rather than using a wildcard.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
images: {
remotePatterns: [
{
protocol: "https",
hostname: "**",
},
],
},
images: {
remotePatterns: [
{
protocol: "https",
hostname: "trusted-image-domain.com",
},
// Add other specific domains as needed
],
},

eslint: {
ignoreDuringBuilds: true,
},
};

export default nextConfig;
41 changes: 41 additions & 0 deletions examples/music-licensing-challenge-nextjs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "music-licensing-challenge",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "biome lint --write",
"lint:check": "biome lint --diagnostic-level=error",
"format": "biome format --write",
"format:check": "biome format",
"prepare": "husky || true",
"lint-staged": "lint-staged",
"type-check": "tsc --noEmit"
},
"dependencies": {
"@apollo/client": "^3.13.8",
"@apollo/client-integration-nextjs": "^0.12.2",
"@headlessui/react": "^2.2.1",
"@heroicons/react": "^2.2.0",
"@tailwindcss/postcss": "^4.1.3",
"clsx": "^2.1.1",
"graphql-ws": "^6.0.4",
"next": "15.2.5",
"next-auth": "5.0.0-beta.25",
"postcss": "^8.5.3",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"tailwindcss": "^4.1.3"
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"husky": "^9.1.7",
"lint-staged": "^15.5.0",
"typescript": "^5"
}
}
Loading