diff --git a/src/client/app.js b/src/client/app.js
index 5e6dd6d7..907d3bed 100644
--- a/src/client/app.js
+++ b/src/client/app.js
@@ -93,29 +93,6 @@ app.config(($locationProvider, $routeProvider) => {
.then(i => i.data)
}
},
- {
- name: '/collective',
- template: '',
- title: 'Преподаватели',
- resolve: {
- list: api => api.teacher
- .list(collectiveSortPattern)
- .then(i => i.data)
- }
- },
- {
- name: '/teacher/:id',
- template: '',
- title: 'Преподаватели',
- resolve: {
- profile: ($route, api) => {
- let id = $route.current.params.id
- return api.teacher
- .fetch(id)
- .then(i => i.data)
- }
- }
- },
{
name: '/awards',
template: '',
diff --git a/src/components/Share.js b/src/components/Share.js
new file mode 100644
index 00000000..5489c466
--- /dev/null
+++ b/src/components/Share.js
@@ -0,0 +1,12 @@
+const React = require('react')
+
+const Share = () => (
+
+
Поделиться
+
Поделиться
+
Отправить
+
Твитнуть
+
+)
+
+module.exports = Share
diff --git a/src/components/TeacherProfile.js b/src/components/TeacherProfile.js
new file mode 100644
index 00000000..9080847c
--- /dev/null
+++ b/src/components/TeacherProfile.js
@@ -0,0 +1,40 @@
+const React = require('react')
+const Share = require('./Share')
+const getHtml = require('../lib/component').getHtml
+
+const Head = ({url, children}) => (
+ !url
+ ? {children}
+ : {children}
+)
+
+const TeacherProfile = ({picture, name, url, profile, biography, shareable}) => (
+
+
+

+
+
+
+
+
{name[0]} {name[1]} {name[2]}
+
+
+
+
{profile.position}
+
{profile.status}
+
Образование: {profile.edu}
+
Диплом: {profile.diploma}
+
+
+
+ {getHtml(biography)}
+
+
+
+ {!shareable ? null : (
+
+ )}
+
+)
+
+module.exports = TeacherProfile
diff --git a/src/core/Teacher.js b/src/core/Teacher.js
new file mode 100644
index 00000000..cdb5b652
--- /dev/null
+++ b/src/core/Teacher.js
@@ -0,0 +1,72 @@
+const Data = require('./Data')
+const Image = require('./Image')
+const {find, findOne} = require('../lib/store')
+
+const store = () => Data.getStore(Teacher)
+
+class Teacher {
+ static async find(query, options = {}) {
+ const items = await find(store(), query, options)
+
+ return Promise.all(items.map(processProfile))
+ }
+
+ static async findById(id) {
+ const data = await findOne(store(), {id})
+ if (!data) return null
+
+ return processProfile(data)
+ }
+
+ constructor(data) {
+ this.id = data.id
+ this.biography = data.biography
+ this.file = data.file
+ this.edu = data.edu
+ this.picture = data.picture
+ this.diploma = data.diploma
+ this.position = data.position
+ this.name = data.name
+ this.status = data.status
+ this.hash = data.hash
+
+ this.url = `/teacher/${this.id}`
+ }
+
+ /**
+ *
+ * "First Middle Last" -> "F. M. Last"
+ *
+ * @returns {string}
+ */
+ shortName() {
+ const f = i => i.replace(/^(.).+/, '$1')
+ const [first, middle, last] = this.splitName()
+
+ return `${f(first)}. ${f(middle)}. ${last}`
+ }
+
+ /**
+ *
+ * "First Middle Last" -> ["First", "Middle", "Last"]
+ *
+ * @returns {Array|{index: number, input: string}}
+ */
+ splitName() {
+ const name = this.name
+ const m = /(.+)\s(.+)\s(.+)/.exec(name)
+ return m.slice(1)
+ }
+}
+
+const processProfile = async profile => {
+ const imageId = profile.picture
+ const picture = await Image.findById(imageId)
+
+ return new Teacher({
+ ...profile,
+ picture,
+ })
+}
+
+module.exports = Teacher
diff --git a/src/core/db.js b/src/core/db.js
index 08ce00fb..ae645b73 100644
--- a/src/core/db.js
+++ b/src/core/db.js
@@ -1,5 +1,6 @@
const Data = require('./Data')
const Album = require('./Album')
+const Teacher = require('./Teacher')
const Image = require('./Image')
const {MongoClient, ObjectId} = require('mongodb')
@@ -28,6 +29,7 @@ export function id(i) {
function init(db) {
Data.setStore(Album, db.collection('albums'))
Data.setStore(Image, db.collection('images'))
+ Data.setStore(Teacher, db.collection('collective'))
return db
}
diff --git a/src/lib/sort.js b/src/lib/sort.js
new file mode 100644
index 00000000..3fa95c00
--- /dev/null
+++ b/src/lib/sort.js
@@ -0,0 +1,37 @@
+function prioritySort(priority, key, list) {
+ priority = priority.reverse()
+
+ let weight = i => {
+ const p = key(i)
+ const index = priority.indexOf(p)
+ return index > -1
+ ? index + 1
+ : 0
+ }
+
+ return sort(list, weight)
+}
+
+function sort(list, fn, reverse = false) {
+ return list
+ .map(i => [fn(i), i])
+ .sort((a, b) => reverse
+ ? a[0] - b[0]
+ : b[0] - a[0])
+ .map(i => i[1])
+}
+
+function sortBy(fn, reverse = false) {
+ return (i1, i2) => {
+ const t1 = fn(i1)
+ const t2 = fn(i2)
+
+ return reverse
+ ? t1 - t2
+ : t2 - t1
+ }
+}
+
+exports.prioritySort = prioritySort
+exports.sortBy = sortBy
+exports.sort = sort
diff --git a/src/models/menu.js b/src/models/menu.js
index 384b61d9..768a2371 100644
--- a/src/models/menu.js
+++ b/src/models/menu.js
@@ -40,9 +40,12 @@ export default [
]
},
{
- 'text': 'Коллектив',
- 'url': '/collective',
- 'color': 'pink'
+ text: 'Коллектив',
+ url: '/collective',
+ color: 'pink',
+ items: [
+ {url: '/teacher/*', text: ''},
+ ]
},
{
text: 'Галерея',
@@ -66,7 +69,7 @@ export default [
{url: 'structure', text: 'Структура и органы управления образовательной организацией'},
{url: 'education', text: 'Образование'},
{url: 'standards', text: 'Образовательные стандарты'},
- {url: '/collective', text: 'Руководство. Педагогический (научно-педагогический) состав'},
+ //{url: '/collective', text: 'Руководство. Педагогический (научно-педагогический) состав'},
{url: 'support', text: 'Материально-техническое обеспечение образовательного процесса'},
{url: 'grants', text: 'Стипендии и иные виды материальной поддержки'},
{url: 'paid-services', text: 'Платные образовательные услуги'},
diff --git a/src/routes/index.js b/src/routes/index.js
index 7f77c529..bffd844b 100644
--- a/src/routes/index.js
+++ b/src/routes/index.js
@@ -8,7 +8,6 @@ import {index as indexFile} from '../config'
import sitemap from './sitemap'
import schedule from './schedule'
import documents from './documents'
-import teachers from './teachers'
import pages from './pages'
export function routes(store) {
@@ -16,7 +15,6 @@ export function routes(store) {
sitemap(),
schedule(),
documents(store),
- teachers(),
pages(),
])
}
diff --git a/src/routes/teachers.js b/src/routes/teachers.js
index 37f0e125..0a1fdd43 100644
--- a/src/routes/teachers.js
+++ b/src/routes/teachers.js
@@ -1,65 +1,100 @@
-import co from 'co';
-import compose from 'koa-compose';
-import route from 'koa-route';
-import {index, json} from './';
-import {sortByPattern} from '../utils/sort';
-import {c} from '../core/db';
+const React = require('react')
+const Article = require('../components/Article')
+const TeacherProfile = require('../components/TeacherProfile')
+const Teacher = require('../core/Teacher')
+const ImageArtifactType = require('../core/ImageArtifactType')
+const {render} = require('../lib/render')
+const {prioritySort} = require('../lib/sort')
+const getPathWithNoTrailingSlash = require('../lib/url').getPathWithNoTrailingSlash
-let split = d => s => s.split(d);
-let toArray = split(',');
+const {get} = require('koa-route')
-export default function () {
- return compose([
- collective(),
- list(),
- teacher()
- ]);
-};
-
-function collective() {
- return route.get('/collective', index());
+function getCollectiveMeta() {
+ return {
+ title: 'Преподаватели',
+ description: 'Преподаватели Шлиссельбургской ДХШ',
+ }
}
-function list() {
- return route.get('/teacher/list', json(
- async(ctx) => {
- ctx.type = 'application/json';
- let pattern = toArray(ctx.query.sort || '');
-
- let data = await c('collective').find().toArray();
- if (!data) {
- ctx.status = 404;
- return;
- }
-
- let collective = await Promise.all(
- data.map(processProfile)
- );
-
- ctx.body = sortByPattern(collective, pattern, i => i.id);
- }
- ));
+function getMeta(teacher) {
+ return {
+ title: teacher.name,
+ description: 'Преподаватель Шлиссельбургской ДХШ',
+ }
}
-function teacher() {
- return route.get('/teacher/:id', json(
- async (ctx, id) => {
- ctx.type = 'application/json';
+const pictureTypes = [
+ ImageArtifactType.BIG,
+ ImageArtifactType.MEDIUM,
+ ImageArtifactType.ORIGIN,
+]
- let data = await c('collective').findOne({id: id});
- if (!data) {
- ctx.status = 404;
- return;
- }
+const profilePicture = profile => profile.picture.findArtifact(pictureTypes)
- ctx.body = await processProfile(data);
- }
- ))
+function getCollective(order) {
+ const teachersSorted = prioritySort.bind(null, order, t => t.id)
+
+ return get('/collective', async ctx => {
+ const path = getPathWithNoTrailingSlash(ctx.path)
+ let teachers = await Teacher.find({})
+
+ if (teachers) {
+ teachers = teachersSorted(teachers)
+
+ const Component = (
+
+

+
+
+ {teachers.map((teacher, index) => (
+
+ ))}
+
+
+ )
+
+ ctx.type = 'text/html'
+ ctx.body = await render(path, Component, getCollectiveMeta(), {menuPadding: false})
+ } else {
+ ctx.status = 404
+ }
+ })
}
-let processProfile = profile => co(function *() {
- let imageId = profile.picture;
- profile.picture = yield c('images').findOne({_id: imageId});
- profile.url = `/teacher/${profile.id}`;
- return profile;
-});
\ No newline at end of file
+function getTeacher() {
+ return get('/teacher/:id', async (ctx, id) => {
+ const path = getPathWithNoTrailingSlash(ctx.path)
+ const teacher = await Teacher.findById(id)
+
+ if (teacher) {
+ const Component = (
+
+
+
+ )
+
+ ctx.type = 'text/html'
+ ctx.body = await render(path, Component, getMeta(teacher), {commentsEnabled: true})
+ } else {
+ ctx.status = 404
+ }
+ })
+
+}
+
+exports.getCollective = getCollective
+exports.getTeacher = getTeacher
diff --git a/src/server.js b/src/server.js
index 88dfa192..e2bbbb67 100644
--- a/src/server.js
+++ b/src/server.js
@@ -24,12 +24,22 @@ const home = require('./routes/home')
const article = require('./routes/articles')
const albums = require('./routes/albums')
const gallery = require('./routes/gallery')
+const teachers = require('./routes/teachers')
const dirPublic = path.join(__dirname, '../public')
const dirTemplates = path.join(__dirname, 'templates')
handlebars.registerHelper('raw-helper', options => options.fn())
+const collectiveOrder = [
+ 'mg-timasheva',
+ 'va-sarzhin',
+ 'od-gogoleva',
+ 'my-valkova',
+ 'vv-voronova',
+ 'nv-andreeva',
+]
+
export default function (store) {
const $ = convert
@@ -58,6 +68,8 @@ export default function (store) {
app.use(article.getArticles(5))
app.use(article.getArticle())
app.use(albums.getAlbum())
+ app.use(teachers.getCollective(collectiveOrder))
+ app.use(teachers.getTeacher())
app.use(routes(store))
return Server(app.callback())
diff --git a/src/style/components/teacher-proifile.scss b/src/style/components/teacher-proifile.scss
index a854ecc9..ae4b6d9a 100644
--- a/src/style/components/teacher-proifile.scss
+++ b/src/style/components/teacher-proifile.scss
@@ -4,13 +4,12 @@ $picture-width: 30%;
$info-width: 100% - $picture-width;
.teacher-profile {
- margin: 0 auto $double-margin;
-
display: flex;
justify-content: space-between;
flex-wrap: wrap;
&__picture {
+ margin: 0 0 $double-margin;
width: $picture-width;
max-width: 15em;
min-width: 12em;
@@ -23,7 +22,8 @@ $info-width: 100% - $picture-width;
&__info {
width: $info-width;
- padding-left: $single-margin;
+ padding-left: $double-margin;
+ margin: 0 0 $double-margin;
box-sizing: border-box;
h2 {