diff --git a/src/components/MicroCountdownTimer/index.js b/src/components/MicroCountdownTimer/index.js index af70214..a1c816d 100644 --- a/src/components/MicroCountdownTimer/index.js +++ b/src/components/MicroCountdownTimer/index.js @@ -29,7 +29,7 @@ const MicroCountdownTimer = () => { }, []); if (timeLeft.days === 0) { - return

HACK NOW!!

; + return

VOTE NOW!!

; } return

{timeLeft.days} days away

; diff --git a/src/components/PageHeader/index.js b/src/components/PageHeader/index.js index 9abbefc..8a6604e 100644 --- a/src/components/PageHeader/index.js +++ b/src/components/PageHeader/index.js @@ -19,7 +19,7 @@ const PageHeader = ({ {title &&

{title}

} {currentYear &&

{currentYear}

} -
+ {/*
{showAddProjectButton && ( )} -
+
*/} ); diff --git a/src/components/header/index.js b/src/components/header/index.js index 932b6d3..9449a2d 100644 --- a/src/components/header/index.js +++ b/src/components/header/index.js @@ -15,7 +15,7 @@ const Header = ({onLogin, onLogout, isAuthenticated, user, showMicroTimer = true
Sentry Logo

- #HACKWEEK + #HACKWEEK

{showMicroTimer && ( diff --git a/src/components/header/styles.css b/src/components/header/styles.css index cb1ded9..a6551e2 100644 --- a/src/components/header/styles.css +++ b/src/components/header/styles.css @@ -73,8 +73,8 @@ } .avatar-container-image { - max-width: 42px; - max-height: 42px; + max-width: 20px; + max-height: 20px; } .avatar-button { diff --git a/src/pages/ProjectList.css b/src/pages/ProjectList.css index 3764daa..38e0fb4 100644 --- a/src/pages/ProjectList.css +++ b/src/pages/ProjectList.css @@ -383,6 +383,50 @@ color: var(--color-gray100); } +.RegionToggle { + display: inline-flex; + background: var(--color-gray400); + border-radius: 10px; + padding: 2px; +} +.RegionToggle button { + appearance: none; + border: 0; + background: transparent; + padding: 0.6rem 0.8rem; + border-radius: 8px; + color: var(--color-gray300); + font-weight: 600; + cursor: pointer; + font-size: 14px; +} +.RegionToggle button:hover { + background: var(--color-gray200); + color: var(--color-gray300); +} +.RegionToggle button.active { + background: var(--color-blurple); + color: white; +} +.RegionToggle button .count { + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 1.25rem; + width: max-content; + padding: 0 0.25em; + min-width: 1.5em; + height: 1.5em; + border-radius: 0.75em; + background: var(--color-gray300); + color: #ffffff; + margin-left: 0.5em; +} +.RegionToggle button.active .count { + background: white; + color: var(--color-blurple); +} + @media (max-width: 639px) { .Project-controls-right { display: none; @@ -495,6 +539,14 @@ background: #e9d8fd; /* lavender tint */ border: 1px solid #d2bfff; } +.Tag--vote { + color: #1d1127; /* gray-100 */ + background: #d1f2ff; /* light blue tint */ + border: 1px solid #b5e6ff; +} +.Tag--vote .vote-label { + font-weight: 400; /* regular weight for "You Voted" */ +} .Tag--help { color: #1d1127; background: #ffd1ea; /* pink tint */ diff --git a/src/pages/ProjectList.js b/src/pages/ProjectList.js index fe944d9..25593cf 100644 --- a/src/pages/ProjectList.js +++ b/src/pages/ProjectList.js @@ -45,6 +45,7 @@ class ProjectListItem extends Component { group: PropTypes.object, submissionsClosed: PropTypes.bool, isOlderYear: PropTypes.bool, + userVote: PropTypes.array, }; render() { @@ -56,6 +57,7 @@ class ProjectListItem extends Component { userList, group, isOlderYear, + userVote, } = this.props; let link = currentYear === project.year @@ -89,8 +91,12 @@ class ProjectListItem extends Component { {/* Project Name */}
{group.id && {group.name}} - {project.needHelp && !submissionsClosed && ( - looking for help + {userVote && userVote.length > 0 && userVote[0].awardCategory && ( + + You Voted{' '} + {awardCategoryOptions[userVote[0].awardCategory]?.name || + userVote[0].awardCategory} + )}
@@ -155,6 +161,7 @@ class ProjectCardItem extends Component { group: PropTypes.object, submissionsClosed: PropTypes.bool, isOlderYear: PropTypes.bool, + userVote: PropTypes.array, }; render() { @@ -166,6 +173,7 @@ class ProjectCardItem extends Component { userList, group, isOlderYear, + userVote, } = this.props; const link = @@ -202,8 +210,12 @@ class ProjectCardItem extends Component {
{group.id && {group.name}} - {project.needHelp && !submissionsClosed && ( - looking for help + {userVote && userVote.length > 0 && userVote[0].awardCategory && ( + + You Voted{' '} + {awardCategoryOptions[userVote[0].awardCategory]?.name || + userVote[0].awardCategory} + )}
@@ -290,6 +302,16 @@ class ProjectList extends Component { this.state = { groupFilter: null, isWide: typeof window !== 'undefined' ? window.innerWidth >= 640 : true, + showIdeasTab: false, // Add this line to hide the Ideas tab + showMyStuffTab: false, // Add this line to hide the My Stuff tab + selectedRegion: 'all', // Default to All Projects + regionCounts: { + westCoast: 0, + eastCoast: 0, + europe: 0, + allProjects: 0, + myVotes: 0, + }, }; } @@ -302,6 +324,114 @@ class ProjectList extends Component { this._handleResize(); } + componentDidUpdate(prevProps) { + // Update region counts when projectList or groupsList changes + if ( + prevProps.projectList !== this.props.projectList || + prevProps.groupsList !== this.props.groupsList + ) { + this.calculateRegionCounts(); + } + + // Update myVotes count when year or auth changes + if (prevProps.year !== this.props.year || prevProps.auth !== this.props.auth) { + this.updateMyVotesCount(); + } + + // Reset region selection if region toggle is hidden + if ( + prevProps.groupsList !== this.props.groupsList && + !this.shouldShowRegionToggle() + ) { + this.setState({selectedRegion: 'all'}); + } + } + + calculateRegionCounts() { + const {projectList, groupsList} = this.props; + if (!projectList || !groupsList) return; + + const projects = mapObject(projectList); + const westCoast = projects.filter((project) => { + const group = groupsList[project.group]; + return ( + group && + (group.name.toLowerCase().includes('west') || + group.name.toLowerCase().includes('california') || + group.name.toLowerCase().includes('seattle')) + ); + }).length; + + const eastCoast = projects.filter((project) => { + const group = groupsList[project.group]; + return ( + group && + (group.name.toLowerCase().includes('east') || + group.name.toLowerCase().includes('new york') || + group.name.toLowerCase().includes('boston')) + ); + }).length; + + const europe = projects.filter((project) => { + const group = groupsList[project.group]; + return ( + group && + (group.name.toLowerCase().includes('europe') || + group.name.toLowerCase().includes('london') || + group.name.toLowerCase().includes('berlin')) + ); + }).length; + + this.setState({ + regionCounts: { + westCoast, + eastCoast, + europe, + allProjects: projects.length, + myVotes: 0, // This will be updated separately since it depends on user votes + }, + }); + } + + updateMyVotesCount() { + const {year, auth} = this.props; + if (!year || !auth) return; + + const userVotes = year ? getAuthUserVotes(auth.uid, year.votes) : []; + this.setState((prevState) => ({ + regionCounts: { + ...prevState.regionCounts, + myVotes: userVotes.length, + }, + })); + } + + shouldShowRegionToggle() { + const {groupsList} = this.props; + if (!groupsList) return false; + + // Check if there are any groups defined for this year + const hasGroups = Object.keys(groupsList).length > 0; + + // Check if any groups have region-related names + const hasRegionGroups = Object.values(groupsList).some( + (group) => + group && + group.name && + (group.name.toLowerCase().includes('west') || + group.name.toLowerCase().includes('east') || + group.name.toLowerCase().includes('europe') || + group.name.toLowerCase().includes('california') || + group.name.toLowerCase().includes('seattle') || + group.name.toLowerCase().includes('new york') || + group.name.toLowerCase().includes('boston') || + group.name.toLowerCase().includes('london') || + group.name.toLowerCase().includes('berlin')) + ); + + return hasGroups && hasRegionGroups; + } + componentWillUnmount() { if (this._handleResize) window.removeEventListener('resize', this._handleResize); } @@ -310,10 +440,16 @@ class ProjectList extends Component { showIdeas, showProjects, showMyProjects, + showMyVotes, ideaCount, projectCount, myProjectsCount, + myVotesCount, viewStyle, + westCoastCount, + eastCoastCount, + europeCount, + allProjectsCount, }) { const {pathname, query} = this.props.location; const currentShow = showIdeas @@ -322,30 +458,84 @@ class ProjectList extends Component { ? 'projects' : showMyProjects ? 'my-projects' + : showMyVotes + ? 'my-votes' : query.show || 'ideas'; const currentView = (this.state.isWide ? viewStyle || query.view : 'list') || 'list'; return (
- - Ideas {ideaCount || 0} - - + Ideas {ideaCount || 0} + + )} + {/* - Projects {projectCount || 0} - - {projectCount || 0} + */} + {this.state.showMyStuffTab && ( + + My Stuff {myProjectsCount || 0} + + )} + {/* - My Stuff {myProjectsCount || 0} - + My Votes {myVotesCount || 0} + */} + + {this.shouldShowRegionToggle() ? ( +
+ + + + + +
+ ) : ( +
+ +
+ )}
{this.state.isWide && ( @@ -378,11 +568,56 @@ class ProjectList extends Component { projectList, userList, groupsList, + year, } = this.props; if (!groupsList) { groupsList = {}; } let projects = mapObject(projectList); + + // Apply region filtering for closed years + if (this.state.selectedRegion !== 'all') { + if (this.state.selectedRegion === 'west') { + projects = projects.filter((project) => { + const group = groupsList[project.group]; + return ( + group && + (group.name.toLowerCase().includes('west') || + group.name.toLowerCase().includes('california') || + group.name.toLowerCase().includes('seattle')) + ); + }); + } else if (this.state.selectedRegion === 'east') { + projects = projects.filter((project) => { + const group = groupsList[project.group]; + return ( + group && + (group.name.toLowerCase().includes('east') || + group.name.toLowerCase().includes('new york') || + group.name.toLowerCase().includes('boston')) + ); + }); + } else if (this.state.selectedRegion === 'europe') { + projects = projects.filter((project) => { + const group = groupsList[project.group]; + return ( + group && + (group.name.toLowerCase().includes('europe') || + group.name.toLowerCase().includes('london') || + group.name.toLowerCase().includes('berlin')) + ); + }); + } else if (this.state.selectedRegion === 'my-votes') { + // Filter for projects the user has voted on + const userVotes = this.props.year + ? getAuthUserVotes(auth.uid, this.props.year.votes) + : []; + projects = projects.filter((project) => + userVotes.some((vote) => vote.project === project.key) + ); + } + } + let winningProjects = []; let otherProjects = []; @@ -395,6 +630,17 @@ class ProjectList extends Component { }); let awardCategoryOptions = getAwardCategories(awardCategoryList); + let userVotes = this.props.year + ? getAuthUserVotes(auth.uid, this.props.year.votes) + : []; + + // Get projects the user has voted on + let myVotedProjects = []; + if (userVotes.length > 0) { + myVotedProjects = projects.filter((project) => + userVotes.some((vote) => vote.project === project.key) + ); + } if (this.state.groupFilter) { if (this.state.groupFilter.value === '') { @@ -411,6 +657,7 @@ class ProjectList extends Component { const showIdeas = !showParam || showParam === 'ideas'; const showProjects = showParam === 'projects'; const showMyProjects = showParam === 'my-projects'; + const showMyVotes = showParam === 'my-votes'; let viewStyle = viewParam === 'grid' ? 'grid' : 'list'; if (!this.state.isWide) viewStyle = 'list'; @@ -430,10 +677,16 @@ class ProjectList extends Component { showIdeas, showProjects, showMyProjects, + showMyVotes, ideaCount: projectIdeas.length, projectCount: actualProjects.length, myProjectsCount: myProjects.length, + myVotesCount: userVotes.length, viewStyle, + westCoastCount: this.state.regionCounts.westCoast, + eastCoastCount: this.state.regionCounts.eastCoast, + europeCount: this.state.regionCounts.europe, + allProjectsCount: this.state.regionCounts.allProjects, })} {showIdeas && projectIdeas.length > 0 && ( @@ -444,6 +697,7 @@ class ProjectList extends Component { v.project === project.key)} firebase={firebase} project={project} awardCategoryOptions={awardCategoryOptions} @@ -461,6 +715,7 @@ class ProjectList extends Component { v.project === project.key)} firebase={firebase} project={project} awardCategoryOptions={awardCategoryOptions} @@ -484,6 +739,7 @@ class ProjectList extends Component { v.project === project.key)} firebase={firebase} project={project} awardCategoryOptions={awardCategoryOptions} @@ -501,6 +757,7 @@ class ProjectList extends Component { v.project === project.key)} firebase={firebase} project={project} awardCategoryOptions={awardCategoryOptions} @@ -516,6 +773,48 @@ class ProjectList extends Component {
)} + {showMyVotes && myVotedProjects.length > 0 && ( +
+ {viewStyle === 'grid' ? ( + + ) : ( + + )} +
+ )} + {showProjects && (
{!!winningProjects.length && ( @@ -527,6 +826,7 @@ class ProjectList extends Component { v.project === project.key)} firebase={firebase} project={project} awardCategoryOptions={awardCategoryOptions} @@ -544,6 +844,7 @@ class ProjectList extends Component { v.project === project.key)} firebase={firebase} project={project} awardCategoryOptions={awardCategoryOptions} @@ -568,6 +869,7 @@ class ProjectList extends Component { v.project === project.key)} firebase={firebase} project={project} awardCategoryOptions={awardCategoryOptions} @@ -585,6 +887,7 @@ class ProjectList extends Component { v.project === project.key)} firebase={firebase} project={project} awardCategoryOptions={awardCategoryOptions} @@ -611,6 +914,7 @@ class ProjectList extends Component { v.project === project.key)} firebase={firebase} project={project} awardCategoryOptions={awardCategoryOptions} @@ -628,6 +932,7 @@ class ProjectList extends Component { v.project === project.key)} firebase={firebase} project={project} awardCategoryOptions={awardCategoryOptions} @@ -673,6 +978,53 @@ class ProjectList extends Component { } let projects = mapObject(projectList); + + // Apply region filtering + if (this.state.selectedRegion !== 'all') { + if (this.state.selectedRegion === 'west') { + projects = projects.filter((project) => { + // Filter for West Coast projects - you can customize this logic + const group = groupsList[project.group]; + return ( + group && + (group.name.toLowerCase().includes('west') || + group.name.toLowerCase().includes('california') || + group.name.toLowerCase().includes('seattle')) + ); + }); + } else if (this.state.selectedRegion === 'east') { + projects = projects.filter((project) => { + // Filter for East Coast projects + const group = groupsList[project.group]; + return ( + group && + (group.name.toLowerCase().includes('east') || + group.name.toLowerCase().includes('new york') || + group.name.toLowerCase().includes('boston')) + ); + }); + } else if (this.state.selectedRegion === 'europe') { + projects = projects.filter((project) => { + // Filter for Europe projects + const group = groupsList[project.group]; + return ( + group && + (group.name.toLowerCase().includes('europe') || + group.name.toLowerCase().includes('london') || + group.name.toLowerCase().includes('berlin')) + ); + }); + } else if (this.state.selectedRegion === 'my-votes') { + // Filter for projects the user has voted on + const userVotes = this.props.year + ? getAuthUserVotes(auth.uid, this.props.year.votes) + : []; + projects = projects.filter((project) => + userVotes.some((vote) => vote.project === project.key) + ); + } + } + if (this.state.groupFilter) { if (this.state.groupFilter.value === '') { projects = projects.filter((project) => !project.group); @@ -697,34 +1049,50 @@ class ProjectList extends Component { const showIdeas = !showParam || showParam === 'ideas'; const showProjects = showParam === 'projects'; const showMyProjects = showParam === 'my-projects'; + const showMyVotes = showParam === 'my-votes'; let viewStyle = viewParam === 'grid' ? 'grid' : 'list'; if (!this.state.isWide) viewStyle = 'list'; + let userVotes = this.props.year + ? getAuthUserVotes(auth.uid, this.props.year.votes) + : []; + let awardCategoryOptions = getAwardCategories(awardCategoryList); + + // Get projects the user has voted on + let myVotedProjects = []; + if (userVotes.length > 0) { + myVotedProjects = projects.filter((project) => + userVotes.some((vote) => vote.project === project.key) + ); + } + const hasAnyProjects = projectsLFH.length > 0 || otherProjects.length > 0; const hasAnyIdeas = projectIdeas.length > 0; const hasAnyMyProjects = myProjects.length > 0; - - let userVotes = year ? getAuthUserVotes(auth.uid, year.votes) : []; - let awardCategoryOptions = getAwardCategories(awardCategoryList); + const hasAnyMyVotes = myVotedProjects.length > 0; let emptyState = null; - if (showProjects && !hasAnyProjects) { + if ((showMyVotes || this.state.selectedRegion === 'my-votes') && !hasAnyMyVotes) { emptyState = (
- Oops! No projects have been created yet for this year! + No votes cast yet! Start voting on projects to see them here.
); - } - if (showIdeas && !hasAnyIdeas) { + } else if (showMyProjects && !hasAnyMyProjects) { + emptyState = ( +
+ Oops! You don't have any projects yet! Create, claim or join a project! +
+ ); + } else if (showIdeas && !hasAnyIdeas) { emptyState = (
Oops! No project ideas have been submitted yet for this year!
); - } - if (showMyProjects && !hasAnyMyProjects) { + } else if (showProjects && !hasAnyProjects) { emptyState = (
- Oops! You don't have any projects yet! Create, claim or join a project! + Oops! No projects have been created yet for this year!
); } @@ -735,10 +1103,16 @@ class ProjectList extends Component { showIdeas, showProjects, showMyProjects, + showMyVotes, ideaCount: projectIdeas.length, projectCount: projectsLFH.length + otherProjects.length, myProjectsCount: myProjects.length, + myVotesCount: userVotes.length, viewStyle, + westCoastCount: this.state.regionCounts.westCoast, + eastCoastCount: this.state.regionCounts.eastCoast, + europeCount: this.state.regionCounts.europe, + allProjectsCount: this.state.regionCounts.allProjects, })} {emptyState} @@ -827,6 +1201,48 @@ class ProjectList extends Component {
)} + {showMyVotes && myVotedProjects.length > 0 && ( +
+ {viewStyle === 'grid' ? ( + + ) : ( + + )} +
+ )} + {showProjects && projectsLFH.length + otherProjects.length > 0 && (
{viewStyle === 'grid' ? ( @@ -912,7 +1328,7 @@ class ProjectList extends Component { currentYear={this.props.params.year || currentYear} showAddProjectButton={!year.submissionsClosed} /> -

+ {/*

Submit your demo videos{' '} {' '} in your group's folder. -

+

*/} {this.renderBody(year)} );