All Tracks/lab fcc forum leaderboard/
Đang tải...
Hướng dẫn thử thách
1 / 1

Build an fCC Forum Leaderboard

In this lab, you will build a freeCodeCamp forum leaderboard that displays the latest topics, users, and replies from the [freeCodeCamp forum](https://forum.freecodecamp.org/). The HTML, CSS and part of the JS have been provided for you. Feel free to explore them. The API endpoint returns JSON in the following shape: ```json { "users": [ { "id": 6, "username": "QuincyLarson", "name": "Quincy Larson", "avatar_template": "/user_avatar/QuincyLarson_{size}.png" }, { "id": 576147, "username": "JOY-OKORO", "name": "Joy Okoro", "avatar_template": "/user_avatar/JOY-OKORO_{size}.png" } ], "topic_list": { "topics": [ { "id": 684569, "title": "The freeCodeCamp Podcast is back – now with video", "slug": "the-freecodecamp-podcast-is-back-now-with-video", "posts_count": 8, "views": 542, "bumped_at": "2024-04-15T16:01:26.403Z", "category_id": 1, "posters": [ { "user_id": 6 }, { "user_id": 576147 } ] } ] } } ``` Note that `avatar_template` values are relative paths: they start with `/` and contain a `{size}` placeholder that should be replaced with a pixel size. The `avatarUrl` constant holds the base URL to prepend when the path is relative. **Objective:** Fulfill the user stories below and get all the tests to pass to complete the lab. **User Stories:** 1. You should have a function named `timeAgo` that takes a timestamp in the ISO 8601 format as the argument. 1. The `timeAgo` function should compute the time difference between the time passed as an argument and the current time and return: - `xm ago` (`x` represents minutes) if the amount of minutes that have passed is less than `60`. - `xh ago` (`x` represents hours) if the amount of hours that have passed is less than `24`. - `xd ago` (`x` represents days) otherwise. 1. You should have a function named `viewCount` that takes the number of views of a post as the argument. 1. If the value of the views passed as the argument is greater than or equal to `1000`, the `viewCount` function should return a string with the views value divided by `1000`, rounded down to the nearest whole number and the letter `k` appended to it. Otherwise, it should return the views value. 1. You should have a function named `forumCategory` that takes the id of a selected category as the argument. 1. The `forumCategory` function should verify that the selected category id is a property of the `allCategories` object and should return a string containing an anchor element with: - the text of the `category` key of the selected category. - a class of `category` followed by the `className` property of the selected category. - an `href` formed by appending `<className>/<id>` to `forumCategoryUrl` (note: `forumCategoryUrl` already ends with `/`, so do not add an extra `/` separator), where `<className>` is the `className` property of the selected category and `id` is the argument passed to `forumCategory`. 1. If the `allCategories` object does not have the selected category id as its property, `category` should be indicated as `General` and `className` should be indicated as `general`. 1. You should have a function named `avatars` that takes two arrays representing posters and users, respectively. 1. The `avatars` function should return a string made by joining `img` elements, one for each `user_id` in the `posters` array. Find the `img` URL by looking up the `user_id` property in the `posters` array and find the matching `id` property in the `users` array. 1. The `avatars` function should set each avatar's size by accessing the `avatar_template` property of the matched user object (found in the `users` array by comparing its `id` to the `user_id` in `posters`) and replacing the `{size}` placeholder in the URL string with `30`. 1. Each image element should have an alt text with the value of the `name` property of the poster. 1. Each `img` element should have a `src` attribute set to the `avatar_template` of the matched user. If `avatar_template` starts with `/`, prepend `avatarUrl` directly to it. 1. You should have a function named `showLatestPosts` that takes a single parameter. 1. The `showLatestPosts` should extract the `users` and `topic_list` properties from the object passed as argument. Also, it should process the following properties of the objects from the `topics` array, which is contained in `topic_list`: - `id`: the id of the post - `title`: the title of the post - `views`: the number of views of the post - `posts_count`: the number of replies to the topic - `slug`: the slug of the post - `posters`: the posters for that topic - `category_id`: an integer indicating the category id for the post - `bumped_at`: a timestamp in the ISO 8601 format 1. The `showLatestPosts` should set the inner HTML of `#posts-container` to a string made by joining `tr` elements, one for each item in `topics`. 1. Each `tr` element should have five `td` elements in it: - a `td` containing two anchor elements, one with the class of `post-title`, an `href` of `<forumTopicUrl><slug>/<id>`, an anchor text of `<title>`, and one obtained by calling `forumCategory` with `category_id`. - a `td` containing a `div` element with class `avatar-container` that contains the images returned by the `avatars` function called with `posters` and `users` as arguments. - a `td` containing the number of replies to the post. _Hint:_ use `posts_count - 1`. - a `td` containing the number of views of the post. - a `td` containing the time passed since the last activity. 1. You should have an async function named `fetchData`. 1. The `fetchData` function should request data from `forumLatest` and call `showLatestPosts` passing it the response parsed as JSON. 1. If there's an error when fetching data, the `fetchData` function should log the error to the console. You should specifically use `console.log` for this. # --before-all-- ```js const _testUsers = [ { avatar_template: '/user_avatar/QuincyLarson_{size}.png', id: 6, name: 'Quincy Larson', username: 'QuincyLarson' }, { avatar_template: '/user_avatar/jwilkins.oboe_{size}.png', id: 285941, name: 'Jessica Wilkins', username: 'jwilkins.oboe' }, { avatar_template: '/user_avatar/ilenia_{size}.png', id: 170865, name: 'Ilenia', username: 'ilenia' } ]; const _testPosters = [ { user_id: 6 }, { user_id: 285941 }, { user_id: 170865 } ]; const _testData = { users: _testUsers, topic_list: { topics: [ { bumped_at: '2024-04-15T16:01:26.403Z', category_id: 1, id: 684569, posters: [{ user_id: 6 }, { user_id: 170865 }, { user_id: 285941 }], posts_count: 8, slug: 'the-freecodecamp-podcast-is-back-now-with-video', title: 'The freeCodeCamp Podcast is back – now with video', views: 542 }, { bumped_at: '2024-04-19T13:52:03.523Z', category_id: 421, id: 686149, posters: [{ user_id: 170865 }], posts_count: 1, slug: 'problem-with-making-changes-to-styles-js', title: 'Problem with making changes to styles. (JS)', views: 9 } ] } }; window.fetch = () => new Promise(resolve => setTimeout( () => resolve({ ok: true, status: 200, statusText: 'OK', json: () => Promise.resolve(_testData), text: () => Promise.resolve(JSON.stringify(_testData)) }), 0 ) ); ```
Vượt qua bài kiểm tra hiện tại để mở khóa bài tiếp theo.
main.go
UTF-8 • Tab Size: 2Kiểm tra bài:⌘↵
Test Output
Thử thách này không có bài test tự động. Hãy quan sát kết quả trực tiếp ở khung Preview.