Feature contacts
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
{
|
||||
"name_fi": "Hallitus",
|
||||
"name_en": "Board",
|
||||
"roles": [
|
||||
{
|
||||
"name_fi": "Puheenjohtaja",
|
||||
"name_en": "Chairman",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Johannes Ora"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Sihteeri",
|
||||
"name_en": "Secretary",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Salla Lyytikäinen",
|
||||
"phone_number": null,
|
||||
"email": null,
|
||||
"image": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Rahastonhoitaja",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Santeri Huhtala",
|
||||
"phone_number": null,
|
||||
"email": null,
|
||||
"image": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Fuksitoimikunnan Puheenjohtaja",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Toni Ojala",
|
||||
"phone_number": null,
|
||||
"email": null,
|
||||
"image": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Fuksitoimikunnan puheenjohtajan adjutantti",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Toni Lyttinen",
|
||||
"phone_number": null,
|
||||
"email": null,
|
||||
"image": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Hovimestari",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Eveliina Ahonen",
|
||||
"phone_number": null,
|
||||
"email": null,
|
||||
"image": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Hovineuvos",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Melissa Dönmez",
|
||||
"phone_number": null,
|
||||
"email": null,
|
||||
"image": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "ISOvastaava",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Heidi Mäkitalo",
|
||||
"phone_number": null,
|
||||
"email": null,
|
||||
"image": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Hyvinvointimestari",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Sauli Norja",
|
||||
"phone_number": null,
|
||||
"email": null,
|
||||
"image": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Opintomestari",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Simo Hakanummi",
|
||||
"phone_number": null,
|
||||
"email": null,
|
||||
"image": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Teknologiamestari",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Oskari Ponkala",
|
||||
"phone_number": null,
|
||||
"email": null,
|
||||
"image": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Ulkomestari",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Oliver Hiekkamies",
|
||||
"phone_number": null,
|
||||
"email": null,
|
||||
"image": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Yrityssuhdemestari",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Otto Julkunen",
|
||||
"phone_number": null,
|
||||
"email": null,
|
||||
"image": null
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name_fi": "Hyvinvointitoimikunta",
|
||||
"name_en": "Wellbeing comittee",
|
||||
"roles": [
|
||||
{
|
||||
"name_fi": "Puheenjohtaja",
|
||||
"name_en": "Chairman",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Oskari Ponkala",
|
||||
"phone_number": null,
|
||||
"email": null,
|
||||
"image": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Web-kisälli",
|
||||
"name_en": "Web-journeyman",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Ilari Ojakorpi",
|
||||
"phone_number": null,
|
||||
"email": null,
|
||||
"image": null
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,18 +1,17 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { Occupation } from "@models/Contacts";
|
||||
import ContactCard from "./ContactCard";
|
||||
import { Committee } from "@views/ContactsPage/ContactsPageView"
|
||||
import { colors } from "@theme/colors";
|
||||
|
||||
interface CommitteeContainerProps {
|
||||
name_fi: string;
|
||||
name_en: string;
|
||||
contacts: Occupation[];
|
||||
committee: Committee;
|
||||
}
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
color: ${colors.darkBlue};
|
||||
|
||||
@@ -28,29 +27,26 @@ const Container = styled.div`
|
||||
& > div {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: flex-start;
|
||||
justify-content: center;
|
||||
}
|
||||
`;
|
||||
|
||||
const CommitteeContainer: React.FC<CommitteeContainerProps> = ({ name_fi, name_en, contacts }) => (
|
||||
const CommitteeContainer: React.FC<CommitteeContainerProps> = ({ committee }) => (
|
||||
<Container>
|
||||
<p>
|
||||
{name_fi}
|
||||
</p>
|
||||
<p>
|
||||
{name_en}
|
||||
{committee.name_fi||committee.name_en}
|
||||
</p>
|
||||
<div>
|
||||
{contacts.map(occupation => (
|
||||
occupation.officials.map(official => (
|
||||
{committee.roles.map(role => (
|
||||
role.representatives.map(representative => (
|
||||
<ContactCard
|
||||
key={official.first_name}
|
||||
first_name={official.first_name}
|
||||
last_name={official.last_name}
|
||||
phone={official.phone_number}
|
||||
email={official.email}
|
||||
image={official.image}
|
||||
role={occupation.role}
|
||||
key={representative.name}
|
||||
name={representative.name}
|
||||
phone={representative.phone_number}
|
||||
email={representative.email}
|
||||
image={representative.image}
|
||||
role_fi={role.name_fi}
|
||||
role_en={role.name_en}
|
||||
/>
|
||||
))
|
||||
))}
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import blank_profile from "@assets/img/blank_profile.png";
|
||||
import { Role } from "@models/Contacts";
|
||||
import { colors } from "@theme/colors";
|
||||
|
||||
const Card = styled.article`
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-flow: row nowrap;
|
||||
padding: 0.5rem;
|
||||
color: ${colors.darkBlue};
|
||||
margin: 1rem;
|
||||
width: 15rem;
|
||||
min-width: 300px;
|
||||
`;
|
||||
|
||||
const ImageContainer = styled.div`
|
||||
padding: 1rem;
|
||||
padding: 0.5rem;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
max-height: 100px;
|
||||
max-width: 100px;
|
||||
height: 6rem;
|
||||
width: 6rem;
|
||||
|
||||
& > img {
|
||||
width: 100%;
|
||||
@@ -30,38 +32,40 @@ const ImageContainer = styled.div`
|
||||
const Info = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0.5rem;
|
||||
justify-content: flex-start;
|
||||
font-size: 1rem;
|
||||
font-weight: 300;
|
||||
align-items: flex-start;
|
||||
padding: 0.25rem;
|
||||
font-size: 0.9rem;
|
||||
color: ${colors.darkBlue};
|
||||
`;
|
||||
|
||||
const Name = styled.text`
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
`
|
||||
|
||||
interface ContactCardProps {
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
phone: number;
|
||||
name: string;
|
||||
phone: string;
|
||||
email: string;
|
||||
image: string;
|
||||
role: Role;
|
||||
role_fi: string;
|
||||
role_en: string;
|
||||
}
|
||||
|
||||
const ContactCard: React.FC<ContactCardProps> = ({ first_name, last_name, phone, email, image, role }) => {
|
||||
const fullName = `${first_name} ${last_name}`;
|
||||
const ContactCard: React.FC<ContactCardProps> = ({ name, phone, email, image, role_fi, role_en }) => {
|
||||
return(
|
||||
<Card>
|
||||
<ImageContainer>
|
||||
<img
|
||||
src={image || blank_profile}
|
||||
alt={fullName}
|
||||
alt={name}
|
||||
/>
|
||||
</ImageContainer>
|
||||
<Info>
|
||||
<p>{fullName}</p>
|
||||
<p>{phone}</p>
|
||||
<p>{email}</p>
|
||||
<p>{role.name_fi}</p>
|
||||
<p>{role.name_en}</p>
|
||||
<Name>{name}</Name>
|
||||
<text>{role_fi || role_en}</text>
|
||||
{phone ? <text>{phone}</text> : null}
|
||||
{email ? <text>{email}</text> : null}
|
||||
</Info>
|
||||
</Card>
|
||||
)
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import axios from "axios";
|
||||
|
||||
const url = `${process.env.API_URL}/contacts`;
|
||||
const committeeUrl = `${process.env.API_URL}/committees`;
|
||||
|
||||
export interface Committee {
|
||||
name_fi: string;
|
||||
name_en: string;
|
||||
}
|
||||
|
||||
export interface Role {
|
||||
name_fi: string;
|
||||
name_en: string;
|
||||
description_fi: string;
|
||||
description_en: string;
|
||||
committee: Committee;
|
||||
is_board: boolean;
|
||||
}
|
||||
|
||||
export interface Contact {
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
phone_number: number;
|
||||
email: string;
|
||||
image: string;
|
||||
}
|
||||
|
||||
export interface Occupation {
|
||||
role: Role;
|
||||
start_date: string;
|
||||
end_date: string;
|
||||
officials: Contact[];
|
||||
}
|
||||
|
||||
export async function getContacts(year: number = new Date().getFullYear()): Promise<Occupation[]> {
|
||||
try {
|
||||
const resp = await axios.get(`${url}?year=${year}`);
|
||||
return resp.data["results"];
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCommittees(): Promise<Committee[]> {
|
||||
try {
|
||||
const resp = await axios.get(`${committeeUrl}`);
|
||||
return resp.data["results"];
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@@ -1,86 +1,14 @@
|
||||
import React from "react";
|
||||
import { Helmet } from "react-helmet";
|
||||
import { StaticContext } from "@server/StaticContext";
|
||||
import { getContacts, Occupation, Committee, getCommittees } from "@models/Contacts";
|
||||
import ContactsPageView from "@views/ContactsPage/ContactsPageView";
|
||||
|
||||
interface ContactsPageProps {
|
||||
staticContext: StaticContext;
|
||||
}
|
||||
|
||||
interface ContactsPageState {
|
||||
contacts: Occupation[];
|
||||
committees: Committee[];
|
||||
}
|
||||
|
||||
class ContactsPage extends React.Component<ContactsPageProps, ContactsPageState> {
|
||||
constructor(props: ContactsPageProps) {
|
||||
super(props);
|
||||
const { staticContext } = props;
|
||||
|
||||
if (staticContext) {
|
||||
/* The static context is an object that manages promises when
|
||||
rendering on the server. If staticContext exists, that means
|
||||
we have to store all promises in it. Otherwise, operate
|
||||
normally. See server/index.ts. */
|
||||
if (staticContext.resolutions.getContacts) {
|
||||
const contacts = staticContext.resolutions.getContacts as Occupation[];
|
||||
const committees = staticContext.resolutions.getCommittees as Committee[];
|
||||
this.state = {
|
||||
contacts,
|
||||
committees,
|
||||
};
|
||||
} else {
|
||||
this.state = {
|
||||
contacts: [],
|
||||
committees: [],
|
||||
};
|
||||
const promiseContacts = this.fetchContacts();
|
||||
const promiseCommittees = this.fetchCommittees();
|
||||
staticContext.promises.getContacts = promiseContacts;
|
||||
staticContext.promises.getCommittees = promiseCommittees;
|
||||
}
|
||||
} else {
|
||||
this.state = {
|
||||
contacts: [],
|
||||
committees: [],
|
||||
};
|
||||
this.fetchContacts();
|
||||
this.fetchCommittees();
|
||||
}
|
||||
}
|
||||
|
||||
fetchContacts = () => {
|
||||
const getContactsPromise = getContacts();
|
||||
getContactsPromise.then(contacts => {
|
||||
this.setState({
|
||||
contacts,
|
||||
});
|
||||
});
|
||||
return getContactsPromise;
|
||||
}
|
||||
|
||||
fetchCommittees = () => {
|
||||
const getCommitteesPromise = getCommittees();
|
||||
getCommitteesPromise.then(committees => {
|
||||
this.setState({
|
||||
committees,
|
||||
});
|
||||
});
|
||||
return getCommitteesPromise;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { contacts, committees } = this.state;
|
||||
return (
|
||||
const ContactsPage: React.FC = () => (
|
||||
<>
|
||||
<Helmet>
|
||||
<link rel="canonical" href="https://sik.ayy.fi/INSERT_PATH_HERE!" />
|
||||
</Helmet>
|
||||
<ContactsPageView contacts={contacts} committees={committees} />
|
||||
<ContactsPageView />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export default ContactsPage;
|
||||
@@ -1,15 +1,11 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { Occupation, Committee } from "@models/Contacts";
|
||||
import CommitteeContainer from "@components/CommitteeContainer";
|
||||
import { Divider, TextSection } from "@components/index";
|
||||
import { colors } from "@theme/colors";
|
||||
import { Link } from "@components/index";
|
||||
|
||||
interface ContactsPageViewProps {
|
||||
contacts: Occupation[];
|
||||
committees: Committee[];
|
||||
}
|
||||
import BoardJson from "@assets/json/board.json";
|
||||
import HvtmkJson from "@assets/json/hvtmk.json";
|
||||
|
||||
const BlueLink = styled(Link)`
|
||||
color: ${colors.blue1};
|
||||
@@ -19,12 +15,26 @@ const BlueLink = styled(Link)`
|
||||
}
|
||||
`;
|
||||
|
||||
export interface Committee {
|
||||
name_fi: string;
|
||||
name_en: string;
|
||||
roles: Array<Role>;
|
||||
}
|
||||
|
||||
class ContactsPageView extends React.Component<ContactsPageViewProps> {
|
||||
render() {
|
||||
const { contacts, committees } = this.props;
|
||||
const board = contacts.filter(x => x.role.is_board);
|
||||
return (
|
||||
export interface Role {
|
||||
name_fi: string;
|
||||
name_en: string;
|
||||
representatives: Array<Representative>
|
||||
}
|
||||
|
||||
export interface Representative {
|
||||
name: string;
|
||||
phone_number?: string;
|
||||
email?: string;
|
||||
image?: string;
|
||||
}
|
||||
|
||||
const ContactsPageView: React.FC = () => (
|
||||
<>
|
||||
<TextSection>
|
||||
<p>
|
||||
@@ -35,7 +45,7 @@ class ContactsPageView extends React.Component<ContactsPageViewProps> {
|
||||
|
||||
<TextSection>
|
||||
<div>
|
||||
<CommitteeContainer name_fi="Hallitus" name_en="Board" contacts={board} />
|
||||
<CommitteeContainer committee={BoardJson} />
|
||||
<p>
|
||||
{"Hallitukseen saa yhteyden lähettämällä sähköpostia "}
|
||||
<BlueLink to="mailto:sik-hallitus@list.ayy.fi">
|
||||
@@ -44,21 +54,17 @@ class ContactsPageView extends React.Component<ContactsPageViewProps> {
|
||||
</p>
|
||||
</div>
|
||||
</TextSection>
|
||||
|
||||
<Divider />
|
||||
{committees.map((committee, index) => {
|
||||
// const order = committee.name_fi === "Toimikunnattomat" ? 1 : 0;
|
||||
return (
|
||||
<>
|
||||
<TextSection key={index}>
|
||||
<CommitteeContainer name_fi={committee.name_fi} name_en={committee.name_en} contacts={contacts.filter(x => x.role.committee.name_fi === committee.name_fi)} />
|
||||
|
||||
<TextSection >
|
||||
<div>
|
||||
<CommitteeContainer committee={HvtmkJson} />
|
||||
</div>
|
||||
</TextSection>
|
||||
<Divider />
|
||||
|
||||
</>
|
||||
)
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
export default ContactsPageView;
|
||||
@@ -3,6 +3,7 @@
|
||||
"outDir": "./dist/",
|
||||
"sourceMap": true,
|
||||
"noImplicitAny": false,
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
// "emitDecoratorMetadata": true,
|
||||
|
||||
Reference in New Issue
Block a user