Skip to content

Commit 5e79474

Browse files
authored
Merge pull request #77 from dzcode-io/65-projects-scene
Added projects scene
2 parents 871923b + 0be3441 commit 5e79474

File tree

14 files changed

+385
-0
lines changed

14 files changed

+385
-0
lines changed

data/projects/list.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"items": ["Algerian_Users"],
3+
"include": ["title"]
4+
}

frontend/src/apps/main/entry/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import "react-toastify/dist/ReactToastify.css";
1313

1414
const Landing = lazy(() => import("t9/apps/main/scenes/landing"));
1515
const Articles = lazy(() => import("t9/apps/main/scenes/articles"));
16+
const Projects = lazy(() => import("t9/apps/main/scenes/projects"));
1617
const Learn = lazy(() => import("t9/apps/main/scenes/learn"));
1718
const Contact = lazy(() => import("t9/apps/main/scenes/contact"));
1819

@@ -86,6 +87,7 @@ export const App: React.SFC<{}> = () => {
8687
<Route path="/" exact={true} component={Landing} />
8788
<Route path="/Learn" component={Learn} />
8889
<Route path="/Articles" component={Articles} />
90+
<Route path="/Projects" component={Projects} />
8991
<Route path="/Contact" component={Contact} />
9092
<Route render={() => <Redirect to="/" />} />
9193
</Switch>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { actionType } from "../../constants";
2+
import { Dispatch } from "react";
3+
import { MainStoreStateInterface } from "t9/types/main";
4+
import Axios from "axios";
5+
import { hasInCollection } from "src/common/utils";
6+
import { Project } from "t9/types/fullstack";
7+
import { fullstackConfig } from "src/config";
8+
9+
const dataURL = fullstackConfig.data.url;
10+
11+
export const fetchProjectsList = () => async (
12+
dispatch: Dispatch<any>,
13+
getState: MainStoreStateInterface,
14+
) => {
15+
try {
16+
const response = await Axios.get(dataURL + "/projects/list.c.json");
17+
dispatch({
18+
type: actionType.UPDATE_PROJECTS_SCENE,
19+
payload: { projectsList: response.data },
20+
});
21+
} catch (error) {
22+
console.error(error);
23+
}
24+
};
25+
26+
export const fetchCurrentProject = () => async (
27+
dispatch: Dispatch<any>,
28+
getState: MainStoreStateInterface,
29+
) => {
30+
const projectSlug = location.pathname.substring(
31+
location.pathname.indexOf("/", 1) + 1,
32+
);
33+
const cashedProject = hasInCollection<Project>(
34+
getState().projects,
35+
"slug",
36+
projectSlug,
37+
[["content"]],
38+
);
39+
if (cashedProject) {
40+
// update our scene state
41+
dispatch({
42+
type: actionType.UPDATE_PROJECTS_SCENE,
43+
payload: { currentProject: cashedProject },
44+
});
45+
} else
46+
try {
47+
const response = await Axios.get(
48+
dataURL + `/projects/${projectSlug}.json`,
49+
);
50+
const currentProject = response.data;
51+
// update our scene state
52+
dispatch({
53+
type: actionType.UPDATE_PROJECTS_SCENE,
54+
payload: { currentProject },
55+
});
56+
// update our cache state
57+
dispatch({
58+
type: actionType.UPDATE_PROJECTS,
59+
payload: [currentProject],
60+
});
61+
} catch (error) {
62+
console.error(error);
63+
}
64+
};

frontend/src/apps/main/redux/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@ export const actionType = {
33
UPDATE_LEARN_SCENE: "UPDATE_LEARN_SCENE",
44
UPDATE_ARTICLES: "UPDATE_ARTICLES",
55
UPDATE_ARTICLES_SCENE: "UPDATE_ARTICLES_SCENE",
6+
UPDATE_PROJECTS: "UPDATE_PROJECTS",
7+
UPDATE_PROJECTS_SCENE: "UPDATE_PROJECTS_SCENE",
68
};

frontend/src/apps/main/redux/reducers/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@ import { documentation } from "./documentation";
33
import { learnScene } from "./learn-scene";
44
import { articles } from "./articles";
55
import { articlesScene } from "./articles-scene";
6+
import { projects } from "./projects";
7+
import { projectsScene } from "./projects-scene";
68

79
export const mainReducer = combineReducers({
810
documentation,
911
learnScene,
1012
articles,
1113
articlesScene,
14+
projects,
15+
projectsScene,
1216
});
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { ProjectsSceneProps } from "t9/apps/main/scenes/projects";
2+
import { actionType } from "t9/apps/main/redux/constants";
3+
4+
export const projectsScene = (
5+
state: ProjectsSceneProps = {
6+
projectsList: null,
7+
currentProject: null,
8+
},
9+
action: {
10+
type: string;
11+
payload: ProjectsSceneProps;
12+
},
13+
) => {
14+
switch (action.type) {
15+
case actionType.UPDATE_PROJECTS_SCENE:
16+
return { ...state, ...action.payload };
17+
default:
18+
return state;
19+
}
20+
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { actionType } from "t9/apps/main/redux/constants";
2+
import { Project } from "t9/types/fullstack";
3+
import { updateCollection } from "src/common/utils";
4+
5+
export const projects = (
6+
state: Project[] = [],
7+
action: {
8+
type: string;
9+
payload: Project[];
10+
},
11+
) => {
12+
switch (action.type) {
13+
case actionType.UPDATE_PROJECTS:
14+
return updateCollection<Project>(state, action.payload, "slug");
15+
default:
16+
return state;
17+
}
18+
};
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React from "react";
2+
import "./style";
3+
import { Project } from "t9/types/fullstack";
4+
import { Link } from "react-router-dom";
5+
6+
export const Catalog = (props: { projectsList: Project[] | null }) => (
7+
<div className="catalog">
8+
{props.projectsList
9+
? props.projectsList.map((project, index) => (
10+
<Link
11+
key={`project-${index}`}
12+
style={{
13+
paddingLeft: `${(project.slug.match(/\//g) || []).length + 1}rem`,
14+
}}
15+
className="item"
16+
to={"/Projects/" + project.slug}
17+
>
18+
{project.title}
19+
</Link>
20+
))
21+
: "Loading Projects List..."}
22+
</div>
23+
);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
@import "../../../../../common/style/variables";
2+
3+
.projects {
4+
.catalog {
5+
padding: 1rem;
6+
width: 100%;
7+
display: inline-block;
8+
.item {
9+
display: block;
10+
padding: 1rem;
11+
cursor: pointer;
12+
}
13+
.item:hover {
14+
background-color: wheat;
15+
}
16+
@media screen and (min-width: $regular) {
17+
width: 20%;
18+
}
19+
}
20+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import React, { useEffect } from "react";
2+
import { Project } from "t9/types/fullstack";
3+
import Markdown from "react-markdown";
4+
import "./style";
5+
6+
import programer from "t9/apps/main/assets/png/programmer.png";
7+
import contact from "t9/apps/main/assets/png/contact.png";
8+
import github from "t9/apps/main/assets/png/github.png";
9+
import support from "t9/apps/main/assets/png/support.png";
10+
11+
const socialMedia = [
12+
{
13+
id: 1,
14+
name: "dzcode",
15+
href: "https://github.com/dzcode-io/dzcode.io",
16+
icon: github,
17+
},
18+
{ id: 2, name: "Learn", href: "/learn", icon: programer },
19+
{ id: 3, name: "Contact", href: "/contact", icon: contact },
20+
{ id: 4, name: "Support", href: "/support", icon: support },
21+
];
22+
23+
export const Details = (props: DetailsInterface) => {
24+
useEffect(() => {
25+
props.fetchCurrentProject();
26+
setTimeout(() => {
27+
window.FB && window.FB.XFBML.parse();
28+
}, 3000);
29+
}, []);
30+
const { currentProject } = props;
31+
return (
32+
<div className="details">
33+
{currentProject ? (
34+
<div>
35+
{/* Image */}
36+
{currentProject.image && (
37+
<img
38+
className="hero-image"
39+
src={currentProject.image}
40+
alt={currentProject.title}
41+
/>
42+
)}
43+
{/* Title */}
44+
<h2 className="title">{currentProject.title}</h2>
45+
{/* Description */}
46+
<small className="description">{currentProject.description}</small>
47+
<hr className="break" />
48+
{/* Details */}
49+
<Markdown className="details" source={currentProject.content} />
50+
<hr className="break" />
51+
{/* Contact + Edit*/}
52+
<div className="actions">
53+
{socialMedia.map((item) => {
54+
return (
55+
<div key={item.id} className="item">
56+
<img src={item.icon} alt={item.name} className="icon" />
57+
<a href={item.href}>{item.name}</a>
58+
</div>
59+
);
60+
})}
61+
</div>
62+
{/* Comments */}
63+
<div
64+
className="fb-comments"
65+
data-href={location.origin + location.pathname}
66+
data-width="100%"
67+
data-numposts="5"
68+
/>
69+
</div>
70+
) : (
71+
"Loading Project..."
72+
)}
73+
</div>
74+
);
75+
};
76+
77+
export interface DetailsInterface {
78+
fetchCurrentProject: () => void;
79+
currentProject: Project | null;
80+
}

0 commit comments

Comments
 (0)