diff --git a/client/config/misc.ts b/client/config/misc.ts index d2fb61fa9a1..ca86710db00 100644 --- a/client/config/misc.ts +++ b/client/config/misc.ts @@ -2,3 +2,4 @@ export const MAX_MOBILE_WIDTH = 767; export const EX_SMALL_VIEWPORT_HEIGHT = 300; export const TOOL_PANEL_HEIGHT = 37; export const SEARCH_EXPOSED_WIDTH = 980; +export const GITHUB_LOCATION = 'https://github.com/freeCodeCamp'; diff --git a/client/i18n/locales/english/translations.json b/client/i18n/locales/english/translations.json index 641dc9348f5..8360bd5a5e9 100644 --- a/client/i18n/locales/english/translations.json +++ b/client/i18n/locales/english/translations.json @@ -125,6 +125,7 @@ "sign-in-with-google": "Sign in with Google", "go-to-dcc-today": "Go to Today's Challenge", "go-to-dcc-archive": "Go to Daily Coding Challenge Archive", + "challenge-source": "View Challenge Source", "outline": "Outline" }, "daily-coding-challenges": { @@ -1421,7 +1422,8 @@ "too-long-three": "Please copy/paste all the editor code showing in the challenge from where you just linked.", "add-code-one": "Replace these two sentences with your copied code.", "add-code-two": "Please leave the ``` line above and the ``` line below,", - "add-code-three": "because they allow your code to properly format in the post." + "add-code-three": "because they allow your code to properly format in the post.", + "git-info": "Github Link: {{gitLink}}" }, "user-token": { "title": "User Token", diff --git a/client/src/components/create-github-link.test.ts b/client/src/components/create-github-link.test.ts new file mode 100644 index 00000000000..47e9bd6d5f7 --- /dev/null +++ b/client/src/components/create-github-link.test.ts @@ -0,0 +1,39 @@ +import { describe, it, expect, vi, afterEach } from 'vitest'; + +describe('generateGitHubLink', () => { + afterEach(() => vi.resetModules()); + it('should return a link to a challenge for an english block', async () => { + vi.doMock('../../config/env.json', () => ({ + default: { + curriculumLocale: 'english' + } + })); + const { generateGithubLink } = await import('./create-github-link'); + const link = generateGithubLink( + '5d5a813321b9e3db6c106a46', + 'learn-basic-javascript-by-building-a-role-playing-game' + ); + + expect(link).toBe( + 'https://github.com/freeCodeCamp/freeCodeCamp/blob/main/curriculum/challenges/english/blocks/learn-basic-javascript-by-building-a-role-playing-game/5d5a813321b9e3db6c106a46.md' + ); + }); + + it('should return a link for a challenge in the Spanish curriculum', async () => { + vi.doMock('../../config/env.json', () => ({ + default: { + curriculumLocale: 'espanol' + } + })); + const { generateGithubLink } = await import('./create-github-link'); + + const link = generateGithubLink( + '5d5a813321b9e3db6c106a46', + 'learn-basic-javascript-by-building-a-role-playing-game' + ); + + expect(link).toBe( + 'https://github.com/freeCodeCamp/i18n-curriculum/blob/main/curriculum/challenges/espanol/blocks/learn-basic-javascript-by-building-a-role-playing-game/5d5a813321b9e3db6c106a46.md' + ); + }); +}); diff --git a/client/src/components/create-github-link.ts b/client/src/components/create-github-link.ts new file mode 100644 index 00000000000..418dd586234 --- /dev/null +++ b/client/src/components/create-github-link.ts @@ -0,0 +1,22 @@ +import envData from '../../config/env.json'; +import { GITHUB_LOCATION } from '../../config/misc'; + +const { curriculumLocale } = envData; + +export const generateGithubLink = (challengeId: string, block: string) => { + const repository = + curriculumLocale === 'english' ? '/freeCodeCamp' : '/i18n-curriculum'; + const gitURL = new URL(GITHUB_LOCATION); + + gitURL.pathname = + gitURL.pathname + + [ + repository, + 'blob/main/curriculum/challenges', + curriculumLocale, + 'blocks', + block, + `${challengeId}.md` + ].join('/'); + return gitURL.toString(); +}; diff --git a/client/src/templates/Challenges/classic/show.tsx b/client/src/templates/Challenges/classic/show.tsx index 2a5990c0193..6a5bc3028ba 100644 --- a/client/src/templates/Challenges/classic/show.tsx +++ b/client/src/templates/Challenges/classic/show.tsx @@ -203,6 +203,7 @@ function ShowClassic({ title, description, instructions, + id, hooks, tests, challengeType, @@ -421,6 +422,8 @@ function ShowClassic({ description={description} instructions={instructions} superBlock={superBlock} + challengeId={id} + block={block} /> } challengeTitle={ diff --git a/client/src/templates/Challenges/components/challenge-description.tsx b/client/src/templates/Challenges/components/challenge-description.tsx index 37adc64d397..98e2d6dbb29 100644 --- a/client/src/templates/Challenges/components/challenge-description.tsx +++ b/client/src/templates/Challenges/components/challenge-description.tsx @@ -2,17 +2,22 @@ import React, { useEffect } from 'react'; import { initializeMathJax, isMathJaxAllowed } from '../../../utils/math-jax'; import PrismFormatted from './prism-formatted'; import './challenge-description.css'; +import { generateGithubLink } from '../../../components/create-github-link'; type Props = { description?: string; instructions?: string; superBlock?: string; + challengeId: string; + block: string; }; const ChallengeDescription = ({ description, instructions, - superBlock + superBlock, + challengeId, + block }: Props) => { useEffect(() => { if (superBlock && isMathJaxAllowed(superBlock)) { @@ -20,10 +25,12 @@ const ChallengeDescription = ({ } }, [superBlock]); + const githubLink = generateGithubLink(challengeId, block); return (