Skip to content
2 changes: 2 additions & 0 deletions api/src/digest/cron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export class DigestCron {
// const projectsFromDataFolder = (await this.dataService.listProjects()).filter((p) =>
// ["dzcode.io website", "Mishkal", "System Monitor"].includes(p.name),
// );
// or uncomment to skip the cron
// if (Math.random()) return;

for (const project of projectsFromDataFolder) {
const projectEntity: ProjectRow = {
Expand Down
16 changes: 11 additions & 5 deletions api/src/project/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,14 @@ export class ProjectRepository {
public async findForList() {
const statement = sql`
SELECT
id,
name,
p.id,
p.name,
sum(repo_with_stats.contributor_count)::int as total_repo_contributor_count,
sum(repo_with_stats.stars)::int as total_repo_stars,
sum(repo_with_stats.score)::int as total_repo_score,
ROUND( 100 * sum(repo_with_stats.contributor_count) + 100 * sum(repo_with_stats.stars) + max(repo_with_stats.score) - sum(repo_with_stats.score) / sum(repo_with_stats.contributor_count) )::int as ranking
ROUND( 100 * sum(repo_with_stats.contributor_count) + 100 * sum(repo_with_stats.stars) + max(repo_with_stats.score) - sum(repo_with_stats.score) / sum(repo_with_stats.contributor_count) )::int as ranking,
COALESCE(array_agg(DISTINCT t.id) filter (where t.id is not null), '{}') as tags

FROM
(
SELECT
Expand All @@ -102,9 +104,13 @@ export class ProjectRepository {
${contributorRepositoryRelationTable.repositoryId}, ${repositoriesTable.projectId}, ${repositoriesTable.stars}
) as repo_with_stats
JOIN
${projectsTable} ON ${projectsTable.id} = repo_with_stats.project_id
${projectsTable} p ON p.id = repo_with_stats.project_id
LEFT JOIN
${projectTagRelationTable} ptr ON p.id = ptr.project_id
LEFT JOIN
tags t ON ptr.tag_id = t.id
GROUP BY
${projectsTable.id}
p.id
ORDER BY
ranking DESC
`;
Expand Down
2 changes: 2 additions & 0 deletions api/src/project/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ContributionEntity } from "@dzcode.io/models/dist/contribution";
import { ContributorEntity } from "@dzcode.io/models/dist/contributor";
import { ProjectEntity } from "@dzcode.io/models/dist/project";
import { RepositoryEntity } from "@dzcode.io/models/dist/repository";
import { TagEntity } from "@dzcode.io/models/dist/tag";
import { GeneralResponse } from "src/app/types";

export interface GetProjectsForSitemapResponse extends GeneralResponse {
Expand All @@ -15,6 +16,7 @@ export interface GetProjectsResponse extends GeneralResponse {
totalRepoScore: number;
totalRepoStars: number;
ranking: number;
tags: TagEntity["id"][];
}
>;
}
Expand Down
2 changes: 1 addition & 1 deletion data/models/projects/Algeria_Covid19_Tracker/info.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"name": "dz-covid19.com"
}
],
"tags": ["by-algerian"]
"tags": ["solve-algerian-problem"]
}
14 changes: 11 additions & 3 deletions web/src/components/locale/dictionary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,17 @@ Besides the open tasks on [/Contribute](/Contribute) page, you can also contribu
en: "Browse a growing list of Algerian open-source projects and be up-to-date with the state of open-source software in Algeria, you can also add your project to the list!",
ar: "تصفح قائمة متزايدة من المشاريع الجزائرية مفتوحة المصدر وكن على اطلاع دائم بأحدث البرامج مفتوحة المصدر في الجزائر ، كما يمكنك إضافة مشروعك إلى القائمة!",
},
"projects-header-title": {
en: "Open Source Projects",
ar: "مشاريع مفتوحة المصدر",
"projects-tag-solve-algerian-problem": {
en: "Solves Algerian Problem",
ar: "يحل مشكلة جزائرية",
},
"projects-tag-by-algerian": {
en: "From an Algerian developer",
ar: "من مطور جزائري",
},
"projects-tag-non-categorized": {
en: "Other",
ar: "أخرى",
},
"projects-card-cta-button": {
en: "Details",
Expand Down
52 changes: 43 additions & 9 deletions web/src/pages/projects/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import React from "react";
import { GetProjectsResponse } from "@dzcode.io/api/dist/project/types";
import React, { Fragment, useMemo } from "react";
import { useEffect } from "react";
import { Helmet } from "react-helmet-async";
import { Loading } from "src/components/loading";
import { Locale, useLocale } from "src/components/locale";
import { DictionaryKeys } from "src/components/locale/dictionary";
import { ProjectCard } from "src/components/project-card";
import { TryAgain } from "src/components/try-again";
import { fetchProjectsListAction } from "src/redux/actions/projects";
Expand All @@ -14,6 +16,34 @@ export default function Page(): JSX.Element {
const { projectsList } = useAppSelector((state) => state.projectsPage);
const dispatch = useAppDispatch();

const projectsGroupedByTag: Array<{
tag: string;
projects: GetProjectsResponse["projects"];
}> = useMemo(() => {
if (projectsList === null || projectsList === "ERROR") return [];

const projectsGroupedByTag: Record<string, GetProjectsResponse["projects"]> = {
"solve-algerian-problem": [],
"by-algerian": [],
"non-categorized": [],
};

projectsList.forEach((project) => {
if (project.tags.includes("solve-algerian-problem")) {
projectsGroupedByTag["solve-algerian-problem"].push(project);
} else if (project.tags.includes("by-algerian")) {
projectsGroupedByTag["by-algerian"].push(project);
} else {
projectsGroupedByTag["non-categorized"].push(project);
}
});

return Object.entries(projectsGroupedByTag).map(([tag, projects]) => ({
tag,
projects,
}));
}, [projectsList]);

useEffect(() => {
dispatch(fetchProjectsListAction());
}, [dispatch]);
Expand All @@ -24,9 +54,6 @@ export default function Page(): JSX.Element {
<title>{localize("projects-title")}</title>
<meta name="description" content={localize("projects-description")} />
</Helmet>
<h1 className="text-xl font-bold m-2 mt-8 self-center">
<Locale projects-header-title />
</h1>

<div className="flex flex-col self-center">
{projectsList === "ERROR" ? (
Expand All @@ -40,11 +67,18 @@ export default function Page(): JSX.Element {
) : projectsList === null ? (
<Loading />
) : (
<div className="flex flex-row flex-wrap gap-4 justify-center p-4 max-w-7xl">
{projectsList.map((project, projectIndex) => (
<ProjectCard project={project} key={projectIndex} />
))}
</div>
projectsGroupedByTag.map((group, groupIndex) => (
<Fragment key={groupIndex}>
<h1 className="text-xl font-bold m-2 mt-8 self-center">
<Locale localeKey={`projects-tag-${group.tag}` as DictionaryKeys<"projects-tag">} />
</h1>
<div className="flex flex-row flex-wrap gap-4 justify-center p-4 max-w-7xl">
{group.projects.map((project, projectIndex) => (
<ProjectCard project={project} key={projectIndex} />
))}
</div>
</Fragment>
))
)}
</div>
</main>
Expand Down
Loading