diff --git a/codewars-badge.js b/codewars-badge.js index 7c26060..650bcf7 100644 --- a/codewars-badge.js +++ b/codewars-badge.js @@ -1,51 +1,274 @@ // This native web component fetches data from the Codewars API and renders it as a badge // Here is some information about web component https://developer.mozilla.org/en-US/docs/Web/Web_Components // Here is the link to the Codewars API Docs: https://dev.codewars.com/#get-user +//the first section is for the searchsection implementation +class CodewarsSearch extends HTMLElement{ + constructor(){ + super(); + this.attachShadow({mode:"open"}); //for isolated styling and structure + } + + connectedCallback(){ + this.render(); //this is the initial render + } + handlingTheSearch(){ + const input = this.shadowRoot.querySelector("#usernameInput"); + const username = input.value.trim(); //input the username and clean it + if(!username) return; //this prevents empty input + //find the badge and change its username + const badge = document.querySelector("codewars-badge"); + if(badge){ + badge.userName = username; //updating the username if the badge exists. + badge.fetchActivity(); //by using badge fetch. + } + const challenges = document.querySelector("codewars-recent-challenges"); + if(challenges){ + challenges.setAttribute("username", username); + } + } + render(){ + this.shadowRoot.innerHTML = ` + +
+ + +
+ `; + //event listener + this.shadowRoot.querySelector("#searchBtn").addEventListener("click", () => this.handlingTheSearch()); + } + } +//defining the new search component +customElements.define("codewars-search", CodewarsSearch); + + +//this implementation is for the codewarsbadge class CodeWarsBadge extends HTMLElement { constructor() { super(); - this.attachShadow({ mode: "open" }); - this.userName = "CodeYourFuture"; - this.userData = []; + this.attachShadow({ mode: "open" });// this creates an isolated DOM or shadow Dom for styling + this.userName = "Mikiyas-STP"; //this holds the codewar username + this.userData = null; //this is set to null to check for empty data } - connectedCallback() { this.fetchActivity() .then(() => { this.render(); }) .catch((error) => { - console.error(error); + console.error("Error fetching Codewars data:", error); + this.renderError(); //to render the error message if the API failed. }); } - // fetch the data from the Codewars API async fetchActivity() { - const response = await fetch( - `https://www.codewars.com/api/v1/users/${this.userName}` - ); - const data = await response.json(); - this.userData = data; // set the userData property with the fetched data + try{ + const response = await fetch(`https://www.codewars.com/api/v1/users/${this.userName}`); + if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`); + const data = await response.json(); + this.userData = data; // set the userData property with the fetched data + this.render(); + }catch (error){ + console.error("Failed to fetch data:", error); + this.userData = null; + this.renderError(); } - +} render() { + if(!this.userData) return; + const rankColor = this.userData.ranks?.overall?.color || "gray"; // Fallback if undefined + const leaderboard = this.userData.leaderboardPosition ? `#${this.userData.leaderboardPosition}` : "N/A"; this.shadowRoot.innerHTML = ` - - ${this.userData.ranks.overall.name} - `; +
+
+

Username:${this.userData.username}

+

Honor Points:${this.userData.honor}

+
+
+ +
+
+

Completed Challenges: ${ + this.userData.codeChallenges.totalCompleted + }

+

Leaderboard Rank: ${leaderboard}

+

Rank:${ + this.userData.ranks.overall.name + }

+
+
` + ; + } + renderError(){ + this.shadowRoot.innerHTML = ` +

Failed to load Codewars data. Please try again later.

`; } } - customElements.define("codewars-badge", CodeWarsBadge); +/* New functionality added for the stretch exercise which is displaying the recent challenges. */ +//creating a new class that extend html element to make the class a web component +class RecentChallenges extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: "open" }); + this.userName = "Mikiyas-STP"; + this.challenges = []; // to store the fetched challenges + } +//this code detects observed attributes of the username + static get observedAttributes() { + return ["username"]; + } +//for the changed username if oldvalue is different from newvalue replace the username with the new value then fetch the challanges. + attributeChangedCallback(name, oldValue, newValue) { + if (name === "username" && oldValue !== newValue) { + this.userName = newValue; + this.fetchChallenges(); + } + } + + connectedCallback() { + this.fetchChallenges() + .then(() => this.render()) + .catch((error) => { + console.error("Error fetching recent challenges:", error); + this.renderError(); + }); + } + async fetchChallenges() { + try { + const res = await fetch( + `https://www.codewars.com/api/v1/users/${this.userName}/code-challenges/completed` + ); + if (!res.ok) throw new Error(`HTTP error! Status: ${res.status}`); + const data = await res.json(); + this.challenges = data.data.slice(0, 5); // Get the latest 5 challenges + this.render(); + } catch (error) { + console.error("Failed to fetch challenges:", error); + this.challenges = null; + this.renderError(); + } + } + render() { + if (!this.challenges) return; + + this.shadowRoot.innerHTML = ` + +
+

Recent Challenges

+ ${this.challenges + .map( + (challenge) => ` +
+

Name: ${challenge.name}

+

Completed At: ${new Date( + challenge.completedAt + ).toLocaleDateString()}

+

View Kata

+
` + ) + .join("")} +
`; + } + renderError() { + this.shadowRoot.innerHTML = ` + +

Failed to load recent challenges. Please try again later.

`; + } +} +customElements.define("codewars-recent-challenges", RecentChallenges); + diff --git a/index.html b/index.html index bbb3149..353be7c 100644 --- a/index.html +++ b/index.html @@ -3,15 +3,14 @@ - Codewars Badge - + Codewars Information Board + + +