- {isBioExpanded ? <>
-
-
-
-
-
-
-
-
+ const insertText = (text) => {
+ const textarea = bioRef.current
+ const startPos = textarea.selectionStart
+ const endPos = textarea.selectionEnd
+ const newValue =
+ textarea.value.substring(0, startPos) +
+ text +
+ textarea.value.substring(endPos, textarea.value.length)
+ setCurrentUsersBio(newValue)
+ textarea.focus()
+ textarea.selectionEnd = startPos + text.length
+ bannerState(true)
+ }
+
+ const magicSnippet = () => {
+ const id = Math.random().toString(36).substring(7)
+ insertText(`[Click to run: ${id}](https://ctfguide.com/magic/)`)
+ }
+
+ function bioViewCheck () {
+ if ((useContext(Context).username) === (user && user.username)) {
+ return true
+ } else {
+ return false
+ }
+ }
-
+ const renderEditButton = () => {
+ return (
+ <>
+ {!isBioExpanded &&
}
+ >
+ )
+ }
+
+ const renderUsersBio = () => {
+ return (
+ <>
+
+
+ {isBioExpanded
+ ? <>
+
-
+
+
+
+
-
+
+
-
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
-
- > : <>
- {user &&
-
-
}
-
- >}
-
-
-
+
+
+ >
+ : <>
+ {user &&
+
+
}
+ >}
- >
- }
+
+
+
+
+ >
+ )
+ }
- const saveBio = async () => {
- const data = {
- bio: currentUsersBio || '',
- };
- try {
- const response = await request(
+ const saveBio = async () => {
+ const data = {
+ bio: currentUsersBio || ''
+ }
+ try {
+ const response = await request(
`${process.env.NEXT_PUBLIC_API_URL}/account`,
'PUT',
data
- );
- console.log(response);
- } catch (err) {
- console.error('Failed to save general information', err);
- }
- closeUnsavedNotif();
+ )
+ console.log(response)
+ } catch (err) {
+ console.error('Failed to save general information', err)
}
-
- async function loadStreakChart() {
- const url = `${process.env.NEXT_PUBLIC_API_URL}/activity/${router.query.user}`;
- const response = await request(url, 'GET', null);
- console.log(response);
- setActivityData(response.body);
+ closeUnsavedNotif()
+ }
+
+ async function loadStreakChart () {
+ const url = `${process.env.NEXT_PUBLIC_API_URL}/activity/${router.query.user}`
+ const response = await request(url, 'GET', null)
+ console.log(response)
+ setActivityData(response.body)
+ }
+
+ async function fetchIsFollowing () {
+ try {
+ const endPoint = `${process.env.NEXT_PUBLIC_API_URL}/followers/${router.query.user}/isFollowing`
+ const result = await request(endPoint, 'GET')
+ setFollowedUser(result.isFollowing)
+ console.log('FOLLOW STATUS: ' + result.isFollowing)
+ } catch (err) {
+ console.error(err)
}
-
- async function fetchIsFollowing() {
- try {
- const endPoint = `${process.env.NEXT_PUBLIC_API_URL}/followers/${router.query.user}/isFollowing`;
- const result = await request(endPoint, 'GET');
- setFollowedUser(result.isFollowing);
- console.log("FOLLOW STATUS: " + result.isFollowing)
- } catch (err) {
- console.error(err);
- }
- }
-
- const handleFollowUser = async () => {
- if (user) {
- try {
- const endPoint = `${process.env.NEXT_PUBLIC_API_URL}/followers/${user.username}/follow`;
- const result = await request(endPoint, 'POST');
- toast.success("You are now following this user.");
- setFollowedUser(true);
- console.log(result);
- } catch (err) {
- console.error(err);
- }
- }
- }
-
- const handleUnfollowUser = async () => {
- try {
- const endPoint = `${process.env.NEXT_PUBLIC_API_URL}/followers/${user.username}/unfollow`;
- const result = await request(endPoint, 'DELETE');
- toast.success("You are no longer following this user.");
- setFollowedUser(false);
- console.log(result);
- } catch (err) {
- console.error(err);
- }
+ }
+
+ const handleFollowUser = async () => {
+ if (user) {
+ try {
+ const endPoint = `${process.env.NEXT_PUBLIC_API_URL}/followers/${user.username}/follow`
+ const result = await request(endPoint, 'POST')
+ toast.success('You are now following this user.')
+ setFollowedUser(true)
+ console.log(result)
+ } catch (err) {
+ console.error(err)
}
+ }
+ }
+
+ const handleUnfollowUser = async () => {
+ try {
+ const endPoint = `${process.env.NEXT_PUBLIC_API_URL}/followers/${user.username}/unfollow`
+ const result = await request(endPoint, 'DELETE')
+ toast.success('You are no longer following this user.')
+ setFollowedUser(false)
+ console.log(result)
+ } catch (err) {
+ console.error(err)
+ }
+ }
-
+ useEffect(() => {
+ if (router.query.user) loadStreakChart()
+ }, [router.query.user])
- useEffect(() => {
- if (router.query.user) loadStreakChart();
- }, [router.query.user]);
+ // Get the Username from Local Storage
+ useEffect(() => {
+ const storedUser = localStorage.getItem('username')
+ if (storedUser) {
+ setUser(storedUser)
+ }
+ }, [])
- // Get the Username from Local Storage
- useEffect(() => {
- const storedUser = localStorage.getItem('username');
- if (storedUser) {
- setUser(storedUser);
- }
- }, []);
-
- // Followers useEffect
- useEffect(() => {
- if (user && user.username) {
- const fetchFollowers = async () => {
- try {
- const endPoint =
+ // Followers useEffect
+ useEffect(() => {
+ if (user && user.username) {
+ const fetchFollowers = async () => {
+ try {
+ const endPoint =
process.env.NEXT_PUBLIC_API_URL +
'/followers/' +
user.username +
- `/followers?page=${followerPage}`;
- const result = await request(endPoint, 'GET');
- if (result && result.followers) {
- setTotalFollowerPages(result.lastPage + 1);
- setFollowers(result.followers);
- setFollowerNum(result.totalEntries);
- }
- } catch (err) {
- console.error(err);
- }
- };
- fetchFollowers();
+ `/followers?page=${followerPage}`
+ const result = await request(endPoint, 'GET')
+ if (result && result.followers) {
+ setTotalFollowerPages(result.lastPage + 1)
+ setFollowers(result.followers)
+ setFollowerNum(result.totalEntries)
+ }
+ } catch (err) {
+ console.error(err)
}
- }, [user, followerPage]);
-
- // Following useEffect
- useEffect(() => {
- if (user && user.username) {
- const fetchFollowing = async () => {
- try {
- const endPoint =
+ }
+ fetchFollowers()
+ }
+ }, [user, followerPage])
+
+ // Following useEffect
+ useEffect(() => {
+ if (user && user.username) {
+ const fetchFollowing = async () => {
+ try {
+ const endPoint =
process.env.NEXT_PUBLIC_API_URL +
'/followers/' +
user.username +
- `/following?page=${followingPage}`;
- const result = await request(endPoint, 'GET');
- if (result && result.following) {
- setTotalFollowingPages(result.lastPage + 1);
- setFollowing(result.following);
- setFollowingNum(result.totalEntries);
- }
- } catch (err) {
- console.error(err);
- }
- };
- fetchFollowing();
+ `/following?page=${followingPage}`
+ const result = await request(endPoint, 'GET')
+ if (result && result.following) {
+ setTotalFollowingPages(result.lastPage + 1)
+ setFollowing(result.following)
+ setFollowingNum(result.totalEntries)
+ }
+ } catch (err) {
+ console.error(err)
}
- }, [user, followingPage]);
+ }
+ fetchFollowing()
+ }
+ }, [user, followingPage])
- const userData = { user, ownUser: true };
+ const userData = { user, ownUser: true }
- // Follower
- const handleFollowerPageChange = (newPage) => {
- if (newPage >= 0 && newPage < totalFollowerPages) {
- setFollowerPage(newPage);
- }
- };
- const nextFollowerPage = () => handleFollowerPageChange(followerPage + 1);
- const prevFollowerPage = () => handleFollowerPageChange(followerPage - 1);
- const followerPageData = {
- setDisplayMode,
- page: followerPage,
- totalPages: totalFollowerPages,
- prevPage: prevFollowerPage,
- nextPage: nextFollowerPage,
- };
-
- // Following
- const handleFollowingPageChange = (newPage) => {
- if (newPage >= 0 && newPage < totalFollowingPages) {
- setFollowingPage(newPage);
- }
- };
- const nextFollowingPage = () => handleFollowingPageChange(followingPage + 1);
- const prevFollowingPage = () => handleFollowingPageChange(followingPage - 1);
- const followingPageData = {
- setDisplayMode,
- page: followingPage,
- totalPages: totalFollowingPages,
- prevPage: prevFollowingPage,
- nextPage: nextFollowingPage,
- };
-
- const radarData = {
- labels: categoryChallenges.map(category => category.name),
- datasets: [
- {
- label: 'Completed Challenges',
- data: categoryChallenges.map(category => category.completed),
- backgroundColor: 'rgba(34, 202, 236, 0.2)',
- borderColor: 'rgba(34, 202, 236, 1)',
- pointBackgroundColor: 'rgba(34, 202, 236, 1)',
- pointBorderColor: '#fff',
- pointHoverBackgroundColor: '#fff',
- pointHoverBorderColor: 'rgba(34, 202, 236, 1)',
- borderWidth: 2,
- },
- ],
- };
-
- const radarOptions = {
- scales: {
- r: {
- angleLines: {
- display: true,
- color: '#444',
- },
- grid: {
- color: '#444',
- },
- pointLabels: {
- color: '#fff',
- font: {
- size: 14,
- },
- },
- ticks: {
- beginAtZero: true,
- min: 0,
- max: 10,
- stepSize: 2,
- showLabelBackdrop: false,
- color: '#fff',
- },
- },
+ // Follower
+ const handleFollowerPageChange = (newPage) => {
+ if (newPage >= 0 && newPage < totalFollowerPages) {
+ setFollowerPage(newPage)
+ }
+ }
+ const nextFollowerPage = () => handleFollowerPageChange(followerPage + 1)
+ const prevFollowerPage = () => handleFollowerPageChange(followerPage - 1)
+ const followerPageData = {
+ setDisplayMode,
+ page: followerPage,
+ totalPages: totalFollowerPages,
+ prevPage: prevFollowerPage,
+ nextPage: nextFollowerPage
+ }
+
+ // Following
+ const handleFollowingPageChange = (newPage) => {
+ if (newPage >= 0 && newPage < totalFollowingPages) {
+ setFollowingPage(newPage)
+ }
+ }
+ const nextFollowingPage = () => handleFollowingPageChange(followingPage + 1)
+ const prevFollowingPage = () => handleFollowingPageChange(followingPage - 1)
+ const followingPageData = {
+ setDisplayMode,
+ page: followingPage,
+ totalPages: totalFollowingPages,
+ prevPage: prevFollowingPage,
+ nextPage: nextFollowingPage
+ }
+
+ const radarData = {
+ labels: categoryChallenges.map(category => category.name),
+ datasets: [
+ {
+ label: 'Completed Challenges',
+ data: categoryChallenges.map(category => category.completed),
+ backgroundColor: 'rgba(34, 202, 236, 0.2)',
+ borderColor: 'rgba(34, 202, 236, 1)',
+ pointBackgroundColor: 'rgba(34, 202, 236, 1)',
+ pointBorderColor: '#fff',
+ pointHoverBackgroundColor: '#fff',
+ pointHoverBorderColor: 'rgba(34, 202, 236, 1)',
+ borderWidth: 2
+ }
+ ]
+ }
+
+ const radarOptions = {
+ scales: {
+ r: {
+ angleLines: {
+ display: true,
+ color: '#444'
},
- plugins: {
- legend: {
- display: false,
- },
- tooltip: {
- callbacks: {
- label: function (context) {
- return `${context.label}: ${context.raw} challenges`;
- },
- },
- },
+ grid: {
+ color: '#444'
},
- };
-
- const pieData = {
- labels: completionData.map(item => item.name),
- datasets: [
- {
- data: completionData.map(item => item.amount),
- backgroundColor: ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6'],
- hoverBackgroundColor: ['#2563eb', '#059669', '#d97706', '#dc2626', '#7c3aed'],
- borderWidth: 0,
- borderRadius: 0,
- cutout: '70%', // This makes it a donut chart
- },
- ],
- };
-
- const pieOptions = {
- plugins: {
- legend: {
- display: false, // Hide the legend
- },
- tooltip: {
- callbacks: {
- label: function (context) {
- const label = context.label || '';
- const value = context.raw || 0;
- return `${label}: ${value} challenges`;
- },
- },
- },
+ pointLabels: {
+ color: '#fff',
+ font: {
+ size: 14
+ }
},
- };
-
- const updatedCompletionData = completionData.map(item => ({
- ...item
- }));
-
- const totalChallenges = completionData.reduce((acc, item) => acc + item.amount, 0);
- const solvedChallenges = totalCompletedChallenges;
-
- const segments = completionData.map(item => ({
- value: (item.amount / totalChallenges) * 100,
- color: item.color.split('-')[1] === 'blue' ? '#3b82f6' :
- item.color.split('-')[1] === 'green' ? '#10b981' :
- item.color.split('-')[1] === 'orange' ? '#f59e0b' :
- item.color.split('-')[1] === 'red' ? '#ef4444' :
- item.color.split('-')[1] === 'purple' ? '#8b5cf6' : '#fff'
- }));
-
- return (
- <>
-
-
{user && user.username}'s Profile - CTFGuide
-
-
-
-
-
-
-
-
-
- {(user && (
-
item.name),
+ datasets: [
+ {
+ data: completionData.map(item => item.amount),
+ backgroundColor: ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6'],
+ hoverBackgroundColor: ['#2563eb', '#059669', '#d97706', '#dc2626', '#7c3aed'],
+ borderWidth: 0,
+ borderRadius: 0,
+ cutout: '70%' // This makes it a donut chart
+ }
+ ]
+ }
+
+ const pieOptions = {
+ plugins: {
+ legend: {
+ display: false // Hide the legend
+ },
+ tooltip: {
+ callbacks: {
+ label: function (context) {
+ const label = context.label || ''
+ const value = context.raw || 0
+ return `${label}: ${value} challenges`
+ }
+ }
+ }
+ }
+ }
+
+ const updatedCompletionData = completionData.map(item => ({
+ ...item
+ }))
+
+ const totalChallenges = completionData.reduce((acc, item) => acc + item.amount, 0)
+ const solvedChallenges = totalCompletedChallenges
+
+ const segments = completionData.map(item => ({
+ value: (item.amount / totalChallenges) * 100,
+ color: item.color.split('-')[1] === 'blue'
+ ? '#3b82f6'
+ : item.color.split('-')[1] === 'green'
+ ? '#10b981'
+ : item.color.split('-')[1] === 'orange'
+ ? '#f59e0b'
+ : item.color.split('-')[1] === 'red'
+ ? '#ef4444'
+ : item.color.split('-')[1] === 'purple' ? '#8b5cf6' : '#fff'
+ }))
+
+ return (
+ <>
+
+ {user && user.username}'s Profile - CTFGuide
+
+
+
+
+
+
+
+
-
-
-
-
-
-
- {(user && user.username) || (
-
- )}
- {user && rank && (
-
- #{rank}
-
- )}
-
-
- {user && user.role === 'ADMIN' && (
-
- developer
-
- )}
-
- {user && user.role === 'PRO' && (
-
- pro
-
- )}
- {!ownUser && followedUser && (
-
-
-
- )}
- {!ownUser && !followedUser && (
-
-
-
- )}
-
-
- {' '}
- {(user && user.location) || (
-
- )}
-
-
-
-
- {user && (
- <>
- setDisplayMode('followers')}
- >
- {' '}
- Followers
- {' '}
- {followerNum || '0'}
- setDisplayMode('following')}
- >
- {' '}
- Following
- {' '}
- {followingNum || '0'}
- >
- )}
-
-
-
-
-
-
+ alt=''
+ />
+ )) || (
+
+ )}
+
+
+
+
+
+
+
+
+ {(user && user.username) || (
+
+ )}
+ {user && rank && (
+
+ #{rank}
+
+ )}
+
+ {user && user.role === 'ADMIN' && (
+
+ developer
+
+ )}
+
+ {user && user.role === 'PRO' && (
+
+ pro
+
+ )}
+ {!ownUser && followedUser && (
+
+
+
+ )}
+ {!ownUser && !followedUser && (
+
+
+
+ )}
+
+
+ {' '}
+ {(user && user.location) || (
+
+ )}
+
+
+
+
+ {user && (
+ <>
+ setDisplayMode('followers')}
+ >
+ {' '}
+ Followers
+ {' '}
+ {followerNum || '0'}
+ setDisplayMode('following')}
+ >
+ {' '}
+ Following
+ {' '}
+ {followingNum || '0'}
+ >
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
SKILL CHART
+ {(categoryChallenges.length > 0 && categoryChallenges.some(category => category.completed > 0))
+ ? (
+
+ )
+ : (
+
+ It seems that {user && user.username} hasn't solved any challenges yet.
+
+ )}
+
+
-
-
-
-
-
-
-
-
SKILL CHART
- {(categoryChallenges.length > 0 && categoryChallenges.some(category => category.completed > 0)) ? (
-
- ) : (
-
- It seems that {user && user.username} hasn't solved any challenges yet.
-
- )}
-
-
-
-
-
-
-
- DIFFICULTY BREAKDOWN
-
- {solvedChallenges > 0 ? (
-
-
-
-
{solvedChallenges} Solved
-
-
- {(
+
+
+
+ DIFFICULTY BREAKDOWN
+
+ {solvedChallenges > 0
+ ? (
+
+
+
+
{solvedChallenges} Solved
+
+
+ {(
completionData.map((item, index) => (
-
-
- {item.name}
-
- {item.amount}
-
+
+
+ {item.name}
+
+ {item.amount}
+
))
)}
-
-
- ) : (
-
Hmm, {user && user.username} hasn't solved any challenges yet.
- )}
-
-
-
-
-
-
-
NERD STATS
- {user && (
-
-
- Creation Date :{' '}
- {new Date(user.createdAt).toLocaleDateString('en-US', {
- month: 'long',
- day: 'numeric',
- year: 'numeric',
- minute: 'numeric',
- hour: 'numeric',
- })}
-
-
Total Challenges: {user.totalChallenges || '0'}
-
Total Writeups: {user.totalWriteups || '0'}
-
Total Badges: {user.totalBadges || '0'}
-
- )}
-
+
-
- {displayMode === 'followers' && (
-
- )}
- {displayMode === 'following' && (
-
+ )
+ : (
+
Hmm, {user && user.username} hasn't solved any challenges yet.
+ )}
+
+
+
+
+
+
NERD STATS
+ {user && (
+
+
+ Creation Date :{' '}
+ {new Date(user.createdAt).toLocaleDateString('en-US', {
+ month: 'long',
+ day: 'numeric',
+ year: 'numeric',
+ minute: 'numeric',
+ hour: 'numeric'
+ })}
+
+
Total Challenges: {user.totalChallenges || '0'}
+
Total Writeups: {user.totalWriteups || '0'}
+
Total Badges: {user.totalBadges || '0'}
+
+ )}
+
+
+
+ {displayMode === 'followers' && (
+
+ )}
+ {displayMode === 'following' && (
+
+ )}
+
+ {displayMode === 'default' && (
+ <>
+
+
+
+
+ {user && (
+
ABOUT {user.username}
)}
+
+ {bioViewCheck() ? renderEditButton() : ''}
- {displayMode === 'default' && (
- <>
-
-
-
-
- {user && (
-
ABOUT {user.username}
- )}
-
- {bioViewCheck() ? renderEditButton():'' }
-
-
-
- {user && user.bio != null ? (
-
- {bioViewCheck() ? renderUsersBio() : user && }
-
-
- ): (
-
- {bioViewCheck() ? renderUsersBio() : user && }
-
- )}
-
-
+ {user && user.bio != null
+ ? (
+
+ {bioViewCheck() ? renderUsersBio() : user && }
+
+
+ )
+ : (
+
+ {bioViewCheck() ? renderUsersBio() : user && }
+
+ )}
-
-
-
-
- {[
- 'SOLVED CHALLENGES',
- 'WRITEUPS',
- 'CREATED CHALLENGES',
-
- ].map((tab) => (
- -
+
+
+
+
+
+
+ {[
+ 'SOLVED CHALLENGES',
+ 'WRITEUPS',
+ 'CREATED CHALLENGES'
+
+ ].map((tab) => (
+ - setActiveTab(tab)}
- >
- {tab}
-
- ))}
-
-
-
-
- {user != undefined && renderContent()}
-
-
-
-
-
-
- ACTIVITY CALENDAR
-
-
- { activityData &&
-
-
- }
- {' '}
-
{' '}
-
{' '}
-
-
-
-
- >
- )}
-
-
+ onClick={() => setActiveTab(tab)}
+ >
+ {tab}
+
+ ))}
+
+
+
+
+ {user != undefined && renderContent()}
-
-
-
-
- {/* are you even surprised atp? */}
- {displayMode === 'followers' || displayMode === 'following' ? (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- ) : null}
-
-
-
- {banner && (
-
-
- You have unsaved changes.
-
-
-
-
+
+
+
+
+ ACTIVITY CALENDAR
+
+
+ {activityData &&
+
}
+ {' '}
+
{' '}
+
{' '}
+
+
+ >
)}
- >
- );
-}
\ No newline at end of file
+
+
+
+
+
+
+
+ {/* are you even surprised atp? */}
+ {displayMode === 'followers' || displayMode === 'following'
+ ? (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )
+ : null}
+
+
+
+ {banner && (
+
+
+ You have unsaved changes.
+
+
+
+
+
+
+ )}
+ >
+ )
+}