feat: update public profile (#7170)

* feat: update public profile

* Update arp@M52V7hmG4ORf4TIVw3W3J.md (#7171)

* Update arp@M52V7hmG4ORf4TIVw3W3J.md

A little changes made to the Topic

* Update src/data/roadmaps/cyber-security/content/arp@M52V7hmG4ORf4TIVw3W3J.md

* Update src/data/roadmaps/cyber-security/content/arp@M52V7hmG4ORf4TIVw3W3J.md

---------

Co-authored-by: Arik Chakma <arikchangma@gmail.com>

* chore: update roadmap content json (#7164)

Co-authored-by: kamranahmedse <4921183+kamranahmedse@users.noreply.github.com>

* Add redis roadmap

* Add redis roadmap

* Add redis roadmap

* Improved Docker Roadmap. 🌨️  (#7029)

* Introduction.

* Namespaces.

* Installation & Setup

* Data Persistence.

* Databases.

* Building Container Images.

* Container Registries.

* Running Containers.

* Container Security

* Docker CLI. (Goated)

* Developer Experience.

* Deploying Containers + Extras.

* Few Refractors.

* Trim Content As Requested.

* Undo / Remove Refractors.

* Update 100-dockerhub.md

* Update 101-dockerhub-alt.md

* Update index.md

* Apply Requested Changes.

* Update what-is-hosting@aqMaEY8gkKMikiqleV5EP.md (#7174)

Add new article for 'Web Hosting', it has clearly explained all the details for the beginners. And it will be more reasonable to have not only videos but also article

* replaced broken link (#7176)

* 7165 roadmap title typo (#7177)

* corrected the node title

* corrected file name

* Fix SEO title

* chore: update roadmap content json (#7173)

Co-authored-by: kamranahmedse <4921183+kamranahmedse@users.noreply.github.com>

* Complete spell-check for "Prespective Analytics" (#7179)

Corrected "Prespective Analytics" into _Prescriptive Analytics_ 


References:
Issue #7165 
PR #7177

* Fix typo in article title (#7180)

* Update 101-memory-management.md (#7181)

* Update 101-memory-management.md

* Update src/data/roadmaps/java/content/101-java-advanced-topics/101-memory-management.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>

* Add cybersecurity content (#7136)

* add 80+ topics

* 7 topics

* 19 topics

* complete cyber roadmap

* expanded internal links into full urls

* Update DevOps roadmap resources (#7081)

* 6 topics

* 6 topics

* 37 topics

* 25 topics

* 53 topics

* finalised the updated content

* Apply suggestions from code review

Co-authored-by: Arik Chakma <arikchangma@gmail.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>

* reverted the removal of go link

---------

Co-authored-by: Arik Chakma <arikchangma@gmail.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>

* chore: update roadmap content json (#7188)

Co-authored-by: kamranahmedse <4921183+kamranahmedse@users.noreply.github.com>

* Update Rendering link to the new React docs (#7205)

* Fix typo (#7202)

* Update technical-documentation@X0xUzEP0S6SyspvqyoDDk.md (#7198)

* Update technical-documentation@X0xUzEP0S6SyspvqyoDDk.md

* Update src/data/roadmaps/devrel/content/technical-documentation@X0xUzEP0S6SyspvqyoDDk.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>

* Update vs-code@j5nNSYI8s-cH8EA6G1EWY.md (#7195)

* Update vs-code@j5nNSYI8s-cH8EA6G1EWY.md

* Update src/data/roadmaps/devrel/content/vs-code@j5nNSYI8s-cH8EA6G1EWY.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>

* Update basic-programming-skills@aSYXa25_0O2qQl1O-N3xl.md (#7193)

* Update basic-programming-skills@aSYXa25_0O2qQl1O-N3xl.md

* Update src/data/roadmaps/devrel/content/basic-programming-skills@aSYXa25_0O2qQl1O-N3xl.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>

* [Update] Software architect: ITIL (#7191)

* [Update] Software architect: ITIL

* [Update] Android roadmap: Firebase docs (#7190)

* [Update] Android roadmap: Firebase docs

* [Update] Android roadmap: Firebase docs

* Chibuike 19/add redis contents (#7186)

* added content to 10 redis topics

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>

* Update links type to official (#7209)

* add link for an article about rendering ,by kentcdodds.com (#7208)

* add link for an article about rendering ,by kentcdodds.com

* Update src/data/roadmaps/react/content/rendering@0uiGsC5SWavNdlFqizkKe.md

---------

Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>

* Fix: Change "virutalenv" to "virtualenv" (#7184)

* Update 102-control-flow.md (#7182)

* feat: update dashboard layout (#7155)

* Update button design for cards

* Default visiblity to all

* Fix qa roadmap issue and public projects

* Update button design for profile

---------

Co-authored-by: Vipul Patil <70363133+1VIP1786@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: kamranahmedse <4921183+kamranahmedse@users.noreply.github.com>
Co-authored-by: Kamran Ahmed <kamranahmed.se@gmail.com>
Co-authored-by: Vedansh <superuser.ntsystems@outlook.com>
Co-authored-by: Jiayou Zhu <43867657+ZlatanCN@users.noreply.github.com>
Co-authored-by: dsh <daniel.s.holdsworth@gmail.com>
Co-authored-by: Sarkis Kovlekjian <83559262+kenshanta@users.noreply.github.com>
Co-authored-by: Mark <mac21macky@gmail.com>
Co-authored-by: Rahul <rahulrp3031@gmail.com>
Co-authored-by: tal bendet <68239430+t-bendet@users.noreply.github.com>
Co-authored-by: Philip B. Krogh <71797726+phibkro@users.noreply.github.com>
Co-authored-by: Brian Rodriguez <rzknairb@gmail.com>
Co-authored-by: Obiechina Emmanuel <94564639+chibuike-19@users.noreply.github.com>
Co-authored-by: Inkyung Huh <inkyung.huh@metric-studio.com>
Co-authored-by: Ahmad Asaad <ahmadasaadh@gmail.com>
feat/changelog^2
Arik Chakma 2 months ago committed by GitHub
parent 3355b91aa0
commit 7642493369
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      src/components/Dashboard/DashboardPage.tsx
  2. 62
      src/components/Dashboard/PersonalDashboard.tsx
  3. 8
      src/components/UpdateProfile/ProfileUsername.tsx
  4. 38
      src/components/UpdateProfile/UpdatePublicProfileForm.tsx
  5. 18
      src/components/UserPublicProfile/UserPublicProfileHeader.tsx
  6. 4
      src/components/UserPublicProfile/UserPublicProjects.tsx
  7. 6814
      src/data/roadmaps/qa/qa.json

@ -54,13 +54,14 @@ export function DashboardPage(props: DashboardPageProps) {
return ( return (
<div className="min-h-screen bg-gray-50 pb-20 pt-8"> <div className="min-h-screen bg-gray-50 pb-20 pt-8">
<div className="container"> <div className="container">
<div className="mb-6 sm:mb-8 flex flex-wrap items-center gap-1.5"> <div className="mb-6 flex flex-wrap items-center gap-1.5 sm:mb-8">
<DashboardTab <DashboardTab
label="Personal" label="Personal"
isActive={!selectedTeamId} isActive={!selectedTeamId}
onClick={() => setSelectedTeamId(undefined)} onClick={() => setSelectedTeamId(undefined)}
avatar={userAvatar} avatar={userAvatar}
/> />
{isLoading && ( {isLoading && (
<> <>
<DashboardTabSkeleton /> <DashboardTabSkeleton />

@ -14,6 +14,9 @@ import { CheckEmoji } from '../ReactIcons/CheckEmoji.tsx';
import { ConstructionEmoji } from '../ReactIcons/ConstructionEmoji.tsx'; import { ConstructionEmoji } from '../ReactIcons/ConstructionEmoji.tsx';
import { BookEmoji } from '../ReactIcons/BookEmoji.tsx'; import { BookEmoji } from '../ReactIcons/BookEmoji.tsx';
import { DashboardAiRoadmaps } from './DashboardAiRoadmaps.tsx'; import { DashboardAiRoadmaps } from './DashboardAiRoadmaps.tsx';
import type { AllowedProfileVisibility } from '../../api/user.ts';
import { PencilIcon, type LucideIcon } from 'lucide-react';
import { cn } from '../../lib/classname.ts';
type UserDashboardResponse = { type UserDashboardResponse = {
name: string; name: string;
@ -21,6 +24,7 @@ type UserDashboardResponse = {
avatar: string; avatar: string;
headline: string; headline: string;
username: string; username: string;
profileVisibility: AllowedProfileVisibility;
progresses: UserProgress[]; progresses: UserProgress[];
projects: ProjectStatusDocument[]; projects: ProjectStatusDocument[];
aiRoadmaps: { aiRoadmaps: {
@ -222,18 +226,20 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
return 0; return 0;
}); });
const { username } = personalDashboardDetails || {};
return ( return (
<section> <section>
{isLoading ? ( {isLoading ? (
<div className="h-7 w-1/4 animate-pulse rounded-lg bg-gray-200"></div> <div className="h-7 w-1/4 animate-pulse rounded-lg bg-gray-200"></div>
) : ( ) : (
<div className="flex items-start sm:items-center justify-between flex-col sm:flex-row gap-1"> <div className="flex flex-col items-start justify-between gap-1 sm:flex-row sm:items-center">
<h2 className="text-lg font-medium"> <h2 className="text-lg font-medium">
Hi {name}, good {getCurrentPeriod()}! Hi {name}, good {getCurrentPeriod()}!
</h2> </h2>
<a <a
href="/home" href="/home"
className="text-xs font-medium bg-gray-200 hover:bg-gray-300 px-2.5 py-1 rounded-full text-gray-700 hover:text-black" className="rounded-full bg-gray-200 px-2.5 py-1 text-xs font-medium text-gray-700 hover:bg-gray-300 hover:text-black"
> >
Visit Homepage Visit Homepage
</a> </a>
@ -253,8 +259,20 @@ export function PersonalDashboard(props: PersonalDashboardProps) {
<DashboardCard <DashboardCard
imgUrl={avatarLink} imgUrl={avatarLink}
title={name!} title={name!}
description="Setup your profile" description={
href="/account/update-profile" username ? 'View your profile' : 'Setup your profile'
}
href={username ? `/u/${username}` : '/account/update-profile'}
{...(username && {
externalLinkIcon: PencilIcon,
externalLinkHref: '/account/update-profile',
externalLinkText: 'Edit',
})}
className={
!username
? 'border-dashed border-gray-500 bg-gray-100 hover:border-gray-500 hover:bg-gray-200'
: ''
}
/> />
<DashboardCard <DashboardCard
@ -312,16 +330,33 @@ type DashboardCardProps = {
title: string; title: string;
description: string; description: string;
href: string; href: string;
externalLinkIcon?: LucideIcon;
externalLinkText?: string;
externalLinkHref?: string;
className?: string;
}; };
function DashboardCard(props: DashboardCardProps) { function DashboardCard(props: DashboardCardProps) {
const { icon: Icon, imgUrl, title, description, href } = props; const {
icon: Icon,
imgUrl,
title,
description,
href,
externalLinkHref,
externalLinkIcon: ExternalLinkIcon,
externalLinkText,
className,
} = props;
return ( return (
<a <div
href={href} className={cn(
className="flex flex-col overflow-hidden rounded-lg border border-gray-300 bg-white hover:border-gray-400 hover:bg-gray-50" 'relative overflow-hidden',
className,
)}
> >
<a href={href} className="flex flex-col rounded-lg border border-gray-300 bg-white hover:border-gray-400 hover:bg-gray-50">
{Icon && ( {Icon && (
<div className="px-4 pb-3 pt-4"> <div className="px-4 pb-3 pt-4">
<Icon className="size-6" /> <Icon className="size-6" />
@ -339,6 +374,17 @@ function DashboardCard(props: DashboardCardProps) {
<p className="text-xs text-black">{description}</p> <p className="text-xs text-black">{description}</p>
</div> </div>
</a> </a>
{externalLinkHref && (
<a
href={externalLinkHref}
className="absolute right-1 top-1 flex items-center gap-1.5 rounded-md bg-gray-200 p-1 px-2 text-xs text-gray-600 hover:bg-gray-300 hover:text-black"
>
{ExternalLinkIcon && <ExternalLinkIcon className="size-3" />}
{externalLinkText}
</a>
)}
</div>
); );
} }

@ -87,15 +87,13 @@ export function ProfileUsername(props: ProfileUsernameProps) {
{currentUsername !== username && username && isUnique && ( {currentUsername !== username && username && isUnique && (
<span className="text-xs text-green-600"> <span className="text-xs text-green-600">
URL after update{' '} URL after update{' '}
<a <span
href={`${import.meta.env.DEV ? 'http://localhost:3000' : 'https://roadmap.sh'}/u/${username}`}
target="_blank"
className={ className={
'ml-0.5 rounded-md border border-purple-500 px-1.5 py-0.5 text-xs font-medium text-purple-700 transition-colors hover:bg-purple-500 hover:text-white' 'ml-0.5 rounded-md border border-purple-500 px-1.5 py-0.5 text-xs font-medium text-purple-700 transition-colors'
} }
> >
roadmap.sh/u/{username} roadmap.sh/u/{username}
</a> </span>
</span> </span>
)} )}
</span> </span>

@ -71,6 +71,7 @@ export function UpdatePublicProfileForm() {
const [profileRoadmaps, setProfileRoadmaps] = useState<RoadmapType[]>([]); const [profileRoadmaps, setProfileRoadmaps] = useState<RoadmapType[]>([]);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [isProfileUpdated, setIsProfileUpdated] = useState(false);
const { isCopied, copyText } = useCopyText(); const { isCopied, copyText } = useCopyText();
@ -109,6 +110,7 @@ export function UpdatePublicProfileForm() {
await loadProfileSettings(); await loadProfileSettings();
toast.success('Profile updated successfully'); toast.success('Profile updated successfully');
setIsProfileUpdated(true);
}; };
const loadProfileSettings = async () => { const loadProfileSettings = async () => {
@ -593,6 +595,42 @@ export function UpdatePublicProfileForm() {
> >
{isLoading ? 'Please wait..' : 'Save Profile'} {isLoading ? 'Please wait..' : 'Save Profile'}
</button> </button>
{isProfileUpdated && publicProfileUrl && (
<div className="flex items-center gap-2">
<button
type="button"
className={cn(
'flex shrink-0 flex-row items-center gap-1 rounded-lg border border-black py-1.5 pl-2.5 pr-3.5 text-xs uppercase text-black transition-colors hover:bg-black hover:text-white',
isCopied
? 'border-green-600 bg-green-600 text-white hover:bg-green-600 hover:text-white'
: '',
)}
onClick={() => {
copyText(`${window.location.origin}${publicProfileUrl}`);
}}
>
{isCopied ? (
<>
<CheckCircle className="size-4" />
Copied Profile URL
</>
) : (
<>
<Copy className="size-4" />
Copy Profile URL
</>
)}
</button>
<a
className='flex shrink-0 flex-row items-center gap-1 rounded-lg border border-black py-1.5 pl-2.5 pr-3.5 text-xs uppercase text-black transition-colors hover:bg-black hover:text-white'
href={publicProfileUrl}
target="_blank"
>
<ArrowUpRight className="size-4" />
View Profile
</a>
</div>
)}
</form> </form>
</div> </div>
); );

@ -3,6 +3,7 @@ import {
Globe, Globe,
LinkedinIcon, LinkedinIcon,
Mail, Mail,
Pencil,
Twitter, Twitter,
} from 'lucide-react'; } from 'lucide-react';
import type { GetPublicProfileResponse } from '../../api/user'; import type { GetPublicProfileResponse } from '../../api/user';
@ -15,11 +16,12 @@ type UserPublicProfileHeaderProps = {
export function UserPublicProfileHeader(props: UserPublicProfileHeaderProps) { export function UserPublicProfileHeader(props: UserPublicProfileHeaderProps) {
const { userDetails } = props; const { userDetails } = props;
const { name, links, publicConfig, avatar, email } = userDetails; const { name, links, publicConfig, avatar, email, isOwnProfile } =
userDetails;
const { headline, isAvailableForHire, isEmailVisible } = publicConfig!; const { headline, isAvailableForHire, isEmailVisible } = publicConfig!;
return ( return (
<div className="container flex items-center gap-6 rounded-xl border bg-white p-8"> <div className="container relative flex items-center gap-6 rounded-xl border bg-white p-8">
<img <img
src={ src={
avatar avatar
@ -27,7 +29,7 @@ export function UserPublicProfileHeader(props: UserPublicProfileHeaderProps) {
: '/images/default-avatar.png' : '/images/default-avatar.png'
} }
alt={name} alt={name}
className="h-32 w-32 object-cover rounded-full" className="h-32 w-32 rounded-full object-cover"
/> />
<div> <div>
@ -51,6 +53,16 @@ export function UserPublicProfileHeader(props: UserPublicProfileHeaderProps) {
{isEmailVisible && <UserLink href={`mailto:${email}`} icon={Mail} />} {isEmailVisible && <UserLink href={`mailto:${email}`} icon={Mail} />}
</div> </div>
</div> </div>
{isOwnProfile && (
<a
href="/account/update-profile"
className="absolute right-4 top-4 flex items-center gap-1.5 text-sm text-gray-500 hover:text-black"
>
<Pencil className="h-3 w-3 stroke-2" />
Edit Profile
</a>
)}
</div> </div>
); );
} }

@ -38,6 +38,10 @@ export function UserPublicProjects(props: UserPublicProjectsProps) {
return 0; return 0;
}) || []; }) || [];
if (!enrichedProjects.length) {
return null;
}
return ( return (
<div className="mt-5"> <div className="mt-5">
<h2 className="mb-2 text-xs uppercase tracking-wide text-gray-400"> <h2 className="mb-2 text-xs uppercase tracking-wide text-gray-400">

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save