From 9fadaa74f086673e0af036637698b0d3d382db91 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 24 Sep 2016 16:26:37 -0300 Subject: [PATCH 01/14] Ivan - Add staff DataStore [skip ci] --- server/controllers/system/init-settings.php | 15 +++++++++++ server/models/Department.php | 11 ++++++++ server/models/Staff.php | 28 +++++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 server/models/Staff.php diff --git a/server/controllers/system/init-settings.php b/server/controllers/system/init-settings.php index f03960c8..e4d81831 100644 --- a/server/controllers/system/init-settings.php +++ b/server/controllers/system/init-settings.php @@ -15,6 +15,7 @@ class InitSettingsController extends Controller { $this->storeGlobalSettings(); $this->storeMailTemplates(); $this->storeMockedDepartments(); + $this->createMockedStaff(); Response::respondSuccess(); } else { @@ -80,4 +81,18 @@ class InitSettingsController extends Controller { $department->store(); } } + + private function createMockedStaff() { + $staff = new Staff(); + $staff->setProperties([ + 'name' => 'Emilia Clarke', + 'email' => 'staff@opensupports.com', + 'password' => Hashing::hashPassword('staff'), + 'profilePic' => 'http://i65.tinypic.com/9bep95.jpg', + 'level' => 1, + 'sharedDepartmentList' => Department::getAllDepartments(), + 'sharedTicketList' => [] + ]); + $staff->store(); + } } \ No newline at end of file diff --git a/server/models/Department.php b/server/models/Department.php index a019bc77..f2c93407 100644 --- a/server/models/Department.php +++ b/server/models/Department.php @@ -21,4 +21,15 @@ class Department extends DataStore { return $departmentsNameList; } + + public static function getAllDepartments() { + $departmentsQuantity = RedBean::count(Department::TABLE); + $departmentList = new DataStoreList(); + + for ($departmentIndex = 1; $departmentIndex <= $departmentsQuantity; ++$departmentIndex) { + $departmentList->add(Department::getDataStore($departmentIndex)); + } + + return $departmentList; + } } \ No newline at end of file diff --git a/server/models/Staff.php b/server/models/Staff.php new file mode 100644 index 00000000..1f5b7084 --- /dev/null +++ b/server/models/Staff.php @@ -0,0 +1,28 @@ + 1 + ]; + } + + public static function getUser($value, $property = 'id') { + return parent::getDataStore($value, $property); + } +} From 528814be0769cc9cf1f4746a304b64140d7411bd Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 24 Sep 2016 16:35:26 -0300 Subject: [PATCH 02/14] Ivan - STAFF LOGIN - Add staff login fixtures [skip ci] --- client/src/data/fixtures/staff-fixtures.js | 22 ++++++++++++++++++++++ client/src/data/fixtures/user-fixtures.js | 1 + client/src/lib-app/fixtures-loader.js | 1 + 3 files changed, 24 insertions(+) create mode 100644 client/src/data/fixtures/staff-fixtures.js diff --git a/client/src/data/fixtures/staff-fixtures.js b/client/src/data/fixtures/staff-fixtures.js new file mode 100644 index 00000000..c4f0a578 --- /dev/null +++ b/client/src/data/fixtures/staff-fixtures.js @@ -0,0 +1,22 @@ +module.exports = [ + { + path: '/staff/get', + time: 100, + response: function () { + return { + status: 'success', + data: { + name: 'Emilia Clarke', + email: 'staff@opensupports.com', + profilePic: 'http://i65.tinypic.com/9bep95.jpg', + level: 1, + departments: [ + {id: 1, name: 'Sales Support'}, + {id: 2, name: 'Technical Issues'}, + {id: 3, name: 'System and Administration'} + ] + } + }; + } + } +]; \ No newline at end of file diff --git a/client/src/data/fixtures/user-fixtures.js b/client/src/data/fixtures/user-fixtures.js index 833678fa..dd72ae59 100644 --- a/client/src/data/fixtures/user-fixtures.js +++ b/client/src/data/fixtures/user-fixtures.js @@ -9,6 +9,7 @@ module.exports = [ response = { status: 'success', data: { + 'staff': data.staff, 'userId': 12, 'token': 'cc6b4921e6733d6aafe284ec0d7be57e', 'rememberToken': (data.remember) ? 'aa41efe0a1b3eeb9bf303e4561ff8392' : null, diff --git a/client/src/lib-app/fixtures-loader.js b/client/src/lib-app/fixtures-loader.js index fcf645a2..896ff338 100644 --- a/client/src/lib-app/fixtures-loader.js +++ b/client/src/lib-app/fixtures-loader.js @@ -17,6 +17,7 @@ let fixtures = (function () { // FIXTURES fixtures.add(require('data/fixtures/user-fixtures')); +fixtures.add(require('data/fixtures/staff-fixtures')); fixtures.add(require('data/fixtures/ticket-fixtures')); fixtures.add(require('data/fixtures/system-fixtures')); From e3650f146f3b3c38081b143e5dbbc029dd799f60 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 24 Sep 2016 17:53:34 -0300 Subject: [PATCH 03/14] Ivan - STAFF LOGIN - Add all routes for admin panel [skip ci] --- client/src/app/Routes.js | 77 +++++++++++++++++-- .../src/app/admin/panel/admin-panel-layout.js | 20 +++++ ...min-panel.scss => admin-panel-layout.scss} | 0 client/src/app/admin/panel/admin-panel.js | 13 ---- .../articles/admin-panel-list-articles.js | 14 ++++ .../articles/admin-panel-view-article.js | 14 ++++ .../panel/dashboard/admin-panel-activity.js | 14 ++++ .../panel/dashboard/admin-panel-my-account.js | 14 ++++ .../panel/dashboard/admin-panel-stats.js | 14 ++++ .../settings/admin-panel-custom-fields.js | 14 ++++ .../settings/admin-panel-email-templates.js | 14 ++++ .../admin-panel-system-preferences.js | 14 ++++ .../panel/settings/admin-panel-user-system.js | 14 ++++ .../panel/staff/admin-panel-departments.js | 14 ++++ .../panel/staff/admin-panel-staff-members.js | 14 ++++ .../panel/staff/admin-panel-view-staff.js | 14 ++++ .../panel/tickets/admin-panel-all-tickets.js | 14 ++++ .../tickets/admin-panel-custom-responses.js | 14 ++++ .../panel/tickets/admin-panel-my-tickets.js | 14 ++++ .../panel/tickets/admin-panel-new-tickets.js | 14 ++++ .../panel/tickets/admin-panel-view-ticket.js | 14 ++++ .../panel/users/admin-panel-ban-users.js | 14 ++++ .../panel/users/admin-panel-list-users.js | 14 ++++ .../panel/users/admin-panel-view-user.js | 14 ++++ 24 files changed, 372 insertions(+), 18 deletions(-) create mode 100644 client/src/app/admin/panel/admin-panel-layout.js rename client/src/app/admin/panel/{admin-panel.scss => admin-panel-layout.scss} (100%) delete mode 100644 client/src/app/admin/panel/admin-panel.js create mode 100644 client/src/app/admin/panel/articles/admin-panel-list-articles.js create mode 100644 client/src/app/admin/panel/articles/admin-panel-view-article.js create mode 100644 client/src/app/admin/panel/dashboard/admin-panel-activity.js create mode 100644 client/src/app/admin/panel/dashboard/admin-panel-my-account.js create mode 100644 client/src/app/admin/panel/dashboard/admin-panel-stats.js create mode 100644 client/src/app/admin/panel/settings/admin-panel-custom-fields.js create mode 100644 client/src/app/admin/panel/settings/admin-panel-email-templates.js create mode 100644 client/src/app/admin/panel/settings/admin-panel-system-preferences.js create mode 100644 client/src/app/admin/panel/settings/admin-panel-user-system.js create mode 100644 client/src/app/admin/panel/staff/admin-panel-departments.js create mode 100644 client/src/app/admin/panel/staff/admin-panel-staff-members.js create mode 100644 client/src/app/admin/panel/staff/admin-panel-view-staff.js create mode 100644 client/src/app/admin/panel/tickets/admin-panel-all-tickets.js create mode 100644 client/src/app/admin/panel/tickets/admin-panel-custom-responses.js create mode 100644 client/src/app/admin/panel/tickets/admin-panel-my-tickets.js create mode 100644 client/src/app/admin/panel/tickets/admin-panel-new-tickets.js create mode 100644 client/src/app/admin/panel/tickets/admin-panel-view-ticket.js create mode 100644 client/src/app/admin/panel/users/admin-panel-ban-users.js create mode 100644 client/src/app/admin/panel/users/admin-panel-list-users.js create mode 100644 client/src/app/admin/panel/users/admin-panel-view-user.js diff --git a/client/src/app/Routes.js b/client/src/app/Routes.js index 389bf918..0470cd27 100644 --- a/client/src/app/Routes.js +++ b/client/src/app/Routes.js @@ -1,5 +1,5 @@ import React from 'react'; -import {Router, Route, IndexRoute, browserHistory} from 'react-router'; +import {Router, Route, IndexRoute, IndexRedirect, browserHistory} from 'react-router'; import { syncHistoryWithStore } from 'react-router-redux'; import store from 'app/store'; @@ -20,8 +20,35 @@ import DashboardEditProfilePage from 'app/main/dashboard/dashboard-edit-profile/ import DashboardArticlePage from 'app/main/dashboard/dashboard-article/dashboard-article-page'; import DashboardTicketPage from 'app/main/dashboard/dashboard-ticket/dashboard-ticket-page'; +// ADMIN PANEL import AdminLoginPage from 'app/admin/admin-login-page'; -import AdminPanel from 'app/admin/panel/admin-panel'; +import AdminPanelLayout from 'app/admin/panel/admin-panel-layout'; + +import AdminPanelStats from 'app/admin/panel/dashboard/admin-panel-stats'; +import AdminPanelActivity from 'app/admin/panel/dashboard/admin-panel-activity'; +import AdminPanelMyAccount from 'app/admin/panel/dashboard/admin-panel-my-account'; + +import AdminPanelMyTickets from 'app/admin/panel/tickets/admin-panel-my-tickets'; +import AdminPanelNewTickets from 'app/admin/panel/tickets/admin-panel-new-tickets'; +import AdminPanelAllTickets from 'app/admin/panel/tickets/admin-panel-all-tickets'; +import AdminPanelViewTicket from 'app/admin/panel/tickets/admin-panel-view-ticket'; +import AdminPanelCustomResponses from 'app/admin/panel/tickets/admin-panel-custom-responses'; + +import AdminPanelListUsers from 'app/admin/panel/users/admin-panel-list-users'; +import AdminPanelViewUser from 'app/admin/panel/users/admin-panel-view-user'; +import AdminPanelBanUsers from 'app/admin/panel/users/admin-panel-ban-users'; + +import AdminPanelListArticles from 'app/admin/panel/articles/admin-panel-list-articles'; +import AdminPanelViewArticle from 'app/admin/panel/articles/admin-panel-view-article'; + +import AdminPanelStaffMembers from 'app/admin/panel/staff/admin-panel-staff-members'; +import AdminPanelDepartments from 'app/admin/panel/staff/admin-panel-departments'; +import AdminPanelViewStaff from 'app/admin/panel/staff/admin-panel-view-staff'; + +import AdminPanelSystemPreferences from 'app/admin/panel/settings/admin-panel-system-preferences'; +import AdminPanelUserSystem from 'app/admin/panel/settings/admin-panel-user-system'; +import AdminPanelEmailTemplates from 'app/admin/panel/settings/admin-panel-email-templates'; +import AdminPanelCustomFields from 'app/admin/panel/settings/admin-panel-custom-fields'; const history = syncHistoryWithStore(browserHistory, store); @@ -43,10 +70,50 @@ export default ( - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/src/app/admin/panel/admin-panel-layout.js b/client/src/app/admin/panel/admin-panel-layout.js new file mode 100644 index 00000000..9ca12fa8 --- /dev/null +++ b/client/src/app/admin/panel/admin-panel-layout.js @@ -0,0 +1,20 @@ +import React from 'react'; +import MainLayout from 'app/main/main-layout'; + +class AdminPanel extends React.Component { + + render() { + return ( + +
+ THIS IS THE ADMIN PANEL +
+
+ {this.props.children} +
+
+ ); + } +} + +export default AdminPanel; \ No newline at end of file diff --git a/client/src/app/admin/panel/admin-panel.scss b/client/src/app/admin/panel/admin-panel-layout.scss similarity index 100% rename from client/src/app/admin/panel/admin-panel.scss rename to client/src/app/admin/panel/admin-panel-layout.scss diff --git a/client/src/app/admin/panel/admin-panel.js b/client/src/app/admin/panel/admin-panel.js deleted file mode 100644 index b0bb5113..00000000 --- a/client/src/app/admin/panel/admin-panel.js +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; - -class AdminPanel extends React.Component { - render(){ - return ( -
- Admin panel... -
- ); - } -} - -export default AdminPanel; \ No newline at end of file diff --git a/client/src/app/admin/panel/articles/admin-panel-list-articles.js b/client/src/app/admin/panel/articles/admin-panel-list-articles.js new file mode 100644 index 00000000..cb607d94 --- /dev/null +++ b/client/src/app/admin/panel/articles/admin-panel-list-articles.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelListArticles extends React.Component { + + render() { + return ( +
+ /admin/panel/articles/list-articles +
+ ); + } +} + +export default AdminPanelListArticles; \ No newline at end of file diff --git a/client/src/app/admin/panel/articles/admin-panel-view-article.js b/client/src/app/admin/panel/articles/admin-panel-view-article.js new file mode 100644 index 00000000..fa026870 --- /dev/null +++ b/client/src/app/admin/panel/articles/admin-panel-view-article.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelViewArticle extends React.Component { + + render() { + return ( +
+ /admin/panel/articles/view-article +
+ ); + } +} + +export default AdminPanelViewArticle; \ No newline at end of file diff --git a/client/src/app/admin/panel/dashboard/admin-panel-activity.js b/client/src/app/admin/panel/dashboard/admin-panel-activity.js new file mode 100644 index 00000000..9b0cc102 --- /dev/null +++ b/client/src/app/admin/panel/dashboard/admin-panel-activity.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelActivity extends React.Component { + + render() { + return ( +
+ /admin/panel/activity +
+ ); + } +} + +export default AdminPanelActivity; \ No newline at end of file diff --git a/client/src/app/admin/panel/dashboard/admin-panel-my-account.js b/client/src/app/admin/panel/dashboard/admin-panel-my-account.js new file mode 100644 index 00000000..9e938cdd --- /dev/null +++ b/client/src/app/admin/panel/dashboard/admin-panel-my-account.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelMyAccount extends React.Component { + + render() { + return ( +
+ /admin/panel/my-account +
+ ); + } +} + +export default AdminPanelMyAccount; \ No newline at end of file diff --git a/client/src/app/admin/panel/dashboard/admin-panel-stats.js b/client/src/app/admin/panel/dashboard/admin-panel-stats.js new file mode 100644 index 00000000..020264e4 --- /dev/null +++ b/client/src/app/admin/panel/dashboard/admin-panel-stats.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelStats extends React.Component { + + render() { + return ( +
+ /admin/panel/stats +
+ ); + } +} + +export default AdminPanelStats; \ No newline at end of file diff --git a/client/src/app/admin/panel/settings/admin-panel-custom-fields.js b/client/src/app/admin/panel/settings/admin-panel-custom-fields.js new file mode 100644 index 00000000..8ffce603 --- /dev/null +++ b/client/src/app/admin/panel/settings/admin-panel-custom-fields.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelCustomFields extends React.Component { + + render() { + return ( +
+ /admin/panel/settings/custom-fields +
+ ); + } +} + +export default AdminPanelCustomFields; \ No newline at end of file diff --git a/client/src/app/admin/panel/settings/admin-panel-email-templates.js b/client/src/app/admin/panel/settings/admin-panel-email-templates.js new file mode 100644 index 00000000..d111b0f6 --- /dev/null +++ b/client/src/app/admin/panel/settings/admin-panel-email-templates.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelEmailTemplates extends React.Component { + + render() { + return ( +
+ /admin/panel/settings/email-templates +
+ ); + } +} + +export default AdminPanelEmailTemplates; \ No newline at end of file diff --git a/client/src/app/admin/panel/settings/admin-panel-system-preferences.js b/client/src/app/admin/panel/settings/admin-panel-system-preferences.js new file mode 100644 index 00000000..cbeafabe --- /dev/null +++ b/client/src/app/admin/panel/settings/admin-panel-system-preferences.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelSystemPreferences extends React.Component { + + render() { + return ( +
+ /admin/panel/settings/system-preferences +
+ ); + } +} + +export default AdminPanelSystemPreferences; \ No newline at end of file diff --git a/client/src/app/admin/panel/settings/admin-panel-user-system.js b/client/src/app/admin/panel/settings/admin-panel-user-system.js new file mode 100644 index 00000000..671bd69b --- /dev/null +++ b/client/src/app/admin/panel/settings/admin-panel-user-system.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelUserSystem extends React.Component { + + render() { + return ( +
+ /admin/panel/settings/user-system +
+ ); + } +} + +export default AdminPanelUserSystem; \ No newline at end of file diff --git a/client/src/app/admin/panel/staff/admin-panel-departments.js b/client/src/app/admin/panel/staff/admin-panel-departments.js new file mode 100644 index 00000000..768add5f --- /dev/null +++ b/client/src/app/admin/panel/staff/admin-panel-departments.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelDepartments extends React.Component { + + render() { + return ( +
+ /admin/panel/staff/departments +
+ ); + } +} + +export default AdminPanelDepartments; \ No newline at end of file diff --git a/client/src/app/admin/panel/staff/admin-panel-staff-members.js b/client/src/app/admin/panel/staff/admin-panel-staff-members.js new file mode 100644 index 00000000..f869fc8b --- /dev/null +++ b/client/src/app/admin/panel/staff/admin-panel-staff-members.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelStaffMembers extends React.Component { + + render() { + return ( +
+ /admin/panel/staff/staff-members +
+ ); + } +} + +export default AdminPanelStaffMembers; \ No newline at end of file diff --git a/client/src/app/admin/panel/staff/admin-panel-view-staff.js b/client/src/app/admin/panel/staff/admin-panel-view-staff.js new file mode 100644 index 00000000..23076093 --- /dev/null +++ b/client/src/app/admin/panel/staff/admin-panel-view-staff.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelViewStaff extends React.Component { + + render() { + return ( +
+ /admin/panel/staff/view-staff +
+ ); + } +} + +export default AdminPanelViewStaff; \ No newline at end of file diff --git a/client/src/app/admin/panel/tickets/admin-panel-all-tickets.js b/client/src/app/admin/panel/tickets/admin-panel-all-tickets.js new file mode 100644 index 00000000..93a4f327 --- /dev/null +++ b/client/src/app/admin/panel/tickets/admin-panel-all-tickets.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelAllTickets extends React.Component { + + render() { + return ( +
+ /admin/panel/tickets/all-tickets +
+ ); + } +} + +export default AdminPanelAllTickets; \ No newline at end of file diff --git a/client/src/app/admin/panel/tickets/admin-panel-custom-responses.js b/client/src/app/admin/panel/tickets/admin-panel-custom-responses.js new file mode 100644 index 00000000..a4d3c1cf --- /dev/null +++ b/client/src/app/admin/panel/tickets/admin-panel-custom-responses.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelCustomResponses extends React.Component { + + render() { + return ( +
+ /admin/panel/tickets/custom-responses +
+ ); + } +} + +export default AdminPanelCustomResponses; \ No newline at end of file diff --git a/client/src/app/admin/panel/tickets/admin-panel-my-tickets.js b/client/src/app/admin/panel/tickets/admin-panel-my-tickets.js new file mode 100644 index 00000000..03a0ffa2 --- /dev/null +++ b/client/src/app/admin/panel/tickets/admin-panel-my-tickets.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelMyTickets extends React.Component { + + render() { + return ( +
+ /admin/panel/tickets/my-tickets +
+ ); + } +} + +export default AdminPanelMyTickets; \ No newline at end of file diff --git a/client/src/app/admin/panel/tickets/admin-panel-new-tickets.js b/client/src/app/admin/panel/tickets/admin-panel-new-tickets.js new file mode 100644 index 00000000..42d250a8 --- /dev/null +++ b/client/src/app/admin/panel/tickets/admin-panel-new-tickets.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelNewTickets extends React.Component { + + render() { + return ( +
+ /admin/panel/tickets/new-tickets +
+ ); + } +} + +export default AdminPanelNewTickets; \ No newline at end of file diff --git a/client/src/app/admin/panel/tickets/admin-panel-view-ticket.js b/client/src/app/admin/panel/tickets/admin-panel-view-ticket.js new file mode 100644 index 00000000..620324bb --- /dev/null +++ b/client/src/app/admin/panel/tickets/admin-panel-view-ticket.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelViewTicket extends React.Component { + + render() { + return ( +
+ /admin/panel/tickets/view-ticket +
+ ); + } +} + +export default AdminPanelViewTicket; \ No newline at end of file diff --git a/client/src/app/admin/panel/users/admin-panel-ban-users.js b/client/src/app/admin/panel/users/admin-panel-ban-users.js new file mode 100644 index 00000000..acb259e4 --- /dev/null +++ b/client/src/app/admin/panel/users/admin-panel-ban-users.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelBanUsers extends React.Component { + + render() { + return ( +
+ /admin/panel/users/ban-users +
+ ); + } +} + +export default AdminPanelBanUsers; \ No newline at end of file diff --git a/client/src/app/admin/panel/users/admin-panel-list-users.js b/client/src/app/admin/panel/users/admin-panel-list-users.js new file mode 100644 index 00000000..8661164e --- /dev/null +++ b/client/src/app/admin/panel/users/admin-panel-list-users.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelListUsers extends React.Component { + + render() { + return ( +
+ /admin/panel/users/list-users +
+ ); + } +} + +export default AdminPanelListUsers; \ No newline at end of file diff --git a/client/src/app/admin/panel/users/admin-panel-view-user.js b/client/src/app/admin/panel/users/admin-panel-view-user.js new file mode 100644 index 00000000..57b828e6 --- /dev/null +++ b/client/src/app/admin/panel/users/admin-panel-view-user.js @@ -0,0 +1,14 @@ +import React from 'react'; + +class AdminPanelViewUser extends React.Component { + + render() { + return ( +
+ /admin/panel/users/view-user +
+ ); + } +} + +export default AdminPanelViewUser; \ No newline at end of file From 3936e772d7460dd58d89a11382e122f565896585 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 24 Sep 2016 18:16:55 -0300 Subject: [PATCH 04/14] Ivan - STAFF LOGIN - Add session architecture for staff login [skip ci] --- client/src/actions/session-actions.js | 6 +++--- client/src/app/App.js | 12 ++++++++++-- client/src/app/admin/admin-login-page.js | 22 +++++++++++++++------- client/src/data/fixtures/staff-fixtures.js | 1 + client/src/reducers/session-reducer.js | 15 ++++++++++++--- 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/client/src/actions/session-actions.js b/client/src/actions/session-actions.js index 90aa07ae..08c95be8 100644 --- a/client/src/actions/session-actions.js +++ b/client/src/actions/session-actions.js @@ -12,7 +12,7 @@ export default { path: '/user/login', data: loginData }).then((result) => { - store.dispatch(this.getUserData(result.data.userId, result.data.token)); + store.dispatch(this.getUserData(result.data.userId, result.data.token, result.data.staff)); return result; }) @@ -49,7 +49,7 @@ export default { }; }, - getUserData(userId, token) { + getUserData(userId, token, staff) { let data = {}; if (userId && token) { @@ -62,7 +62,7 @@ export default { return { type: 'USER_DATA', payload: API.call({ - path: '/user/get', + path: (staff) ? '/staff/get' : '/user/get', data: data }) } diff --git a/client/src/app/App.js b/client/src/app/App.js index 00f2efdf..90197430 100644 --- a/client/src/app/App.js +++ b/client/src/app/App.js @@ -44,7 +44,9 @@ class App extends React.Component { const validations = { languageChanged: props.config.language !== this.props.config.language, loggedIn: !_.includes(props.location.pathname, '/dashboard') && props.session.logged, - loggedOut: _.includes(props.location.pathname, '/dashboard') && !props.session.logged + loggedOut: _.includes(props.location.pathname, '/dashboard') && !props.session.logged, + loggedInStaff: !_.includes(props.location.pathname, '/admin/panel') && props.session.staff, + loggedOutStaff: _.includes(props.location.pathname, '/admin/panel') && !props.session.logged }; if (validations.languageChanged) { @@ -55,8 +57,14 @@ class App extends React.Component { browserHistory.push('/'); } - if (validations.loggedIn) { + if (validations.loggedOutStaff) { + browserHistory.push('/admin'); + } + + if (validations.loggedIn && !props.session.staff) { browserHistory.push('/dashboard'); + } else if(validations.loggedInStaff) { + browserHistory.push('/admin/panel'); } } } diff --git a/client/src/app/admin/admin-login-page.js b/client/src/app/admin/admin-login-page.js index e4727f21..12d74dc5 100644 --- a/client/src/app/admin/admin-login-page.js +++ b/client/src/app/admin/admin-login-page.js @@ -1,23 +1,25 @@ import React from 'react'; +import _ from 'lodash'; +import {connect} from 'react-redux'; import i18n from 'lib-app/i18n'; -import API from 'lib-app/api-call'; +import SessionActions from 'actions/session-actions'; import Form from 'core-components/form'; import FormField from 'core-components/form-field'; import SubmitButton from 'core-components/submit-button'; class AdminLoginPage extends React.Component { - render(){ + render() { return (
OpenSupports Admin Panel
-
+ - - {i18n('LOG_IN')} + + {i18n('LOG_IN')}
@@ -26,8 +28,14 @@ class AdminLoginPage extends React.Component { } onSubmit(formState) { - + this.props.dispatch(SessionActions.login(_.extend({}, formState, { + staff: true + }))); } } -export default AdminLoginPage; \ No newline at end of file +export default connect((store) => { + return { + session: store.session + }; +})(AdminLoginPage); diff --git a/client/src/data/fixtures/staff-fixtures.js b/client/src/data/fixtures/staff-fixtures.js index c4f0a578..ea6afbcd 100644 --- a/client/src/data/fixtures/staff-fixtures.js +++ b/client/src/data/fixtures/staff-fixtures.js @@ -10,6 +10,7 @@ module.exports = [ email: 'staff@opensupports.com', profilePic: 'http://i65.tinypic.com/9bep95.jpg', level: 1, + staff: true, departments: [ {id: 1, name: 'Sales Support'}, {id: 2, name: 'Technical Issues'}, diff --git a/client/src/reducers/session-reducer.js b/client/src/reducers/session-reducer.js index 877bb590..92251dce 100644 --- a/client/src/reducers/session-reducer.js +++ b/client/src/reducers/session-reducer.js @@ -41,7 +41,8 @@ class SessionReducer extends Reducer { return _.extend({}, state, { logged: true, pending: false, - failed: false + failed: false, + staff: payload.data.staff }); } @@ -101,8 +102,12 @@ class SessionReducer extends Reducer { sessionStore.storeUserData(payload.data); return _.extend({}, state, { - userName: userData.name, - userEmail: userData.email, + staff: userData.staff, + userName: userData.name, + userEmail: userData.email, + userProfilePic: userData.profilePic, + userLevel: userData.level, + userDepartments: userData.departments, userTickets: userData.tickets }); } @@ -113,8 +118,12 @@ class SessionReducer extends Reducer { return _.extend({}, state, { initDone: true, logged: true, + staff: userData.staff, userName: userData.name, userEmail: userData.email, + userProfilePic: userData.profilePic, + userLevel: userData.level, + userDepartments: userData.departments, userTickets: userData.tickets }); } From b5dcaa900912b44c2057f702dfcd84c9fa63c6e3 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 24 Sep 2016 20:19:24 -0300 Subject: [PATCH 05/14] Ivan - STAFF LOGIN - Add header for staff panel with profile pic and menu [skip ci] --- .../src/app/admin/panel/admin-panel-layout.js | 26 ++- .../app/admin/panel/admin-panel-layout.scss | 7 + .../src/app/admin/panel/admin-panel-menu.js | 203 ++++++++++++++++++ .../src/app/admin/panel/admin-panel-menu.scss | 3 + .../admin/panel/admin-panel-staff-widget.js | 47 ++++ .../admin/panel/admin-panel-staff-widget.scss | 47 ++++ client/src/data/languages/en.js | 19 ++ 7 files changed, 347 insertions(+), 5 deletions(-) create mode 100644 client/src/app/admin/panel/admin-panel-menu.js create mode 100644 client/src/app/admin/panel/admin-panel-menu.scss create mode 100644 client/src/app/admin/panel/admin-panel-staff-widget.js create mode 100644 client/src/app/admin/panel/admin-panel-staff-widget.scss diff --git a/client/src/app/admin/panel/admin-panel-layout.js b/client/src/app/admin/panel/admin-panel-layout.js index 9ca12fa8..59a5e7d9 100644 --- a/client/src/app/admin/panel/admin-panel-layout.js +++ b/client/src/app/admin/panel/admin-panel-layout.js @@ -1,16 +1,32 @@ import React from 'react'; + import MainLayout from 'app/main/main-layout'; +import AdminPanelStaffWidget from 'app/admin/panel/admin-panel-staff-widget'; +import AdminPanelMenu from 'app/admin/panel/admin-panel-menu'; + +import Widget from 'core-components/widget'; class AdminPanel extends React.Component { render() { return ( -
- THIS IS THE ADMIN PANEL -
-
- {this.props.children} +
+
+
+ +
+
+ +
+
+
+
+ + {this.props.children} + +
+
); diff --git a/client/src/app/admin/panel/admin-panel-layout.scss b/client/src/app/admin/panel/admin-panel-layout.scss index e69de29b..42a68014 100644 --- a/client/src/app/admin/panel/admin-panel-layout.scss +++ b/client/src/app/admin/panel/admin-panel-layout.scss @@ -0,0 +1,7 @@ +.admin-panel-layout { + padding: 0 10px; + + &__header { + margin-bottom: 20px; + } +} \ No newline at end of file diff --git a/client/src/app/admin/panel/admin-panel-menu.js b/client/src/app/admin/panel/admin-panel-menu.js new file mode 100644 index 00000000..de97eaf4 --- /dev/null +++ b/client/src/app/admin/panel/admin-panel-menu.js @@ -0,0 +1,203 @@ +import React from 'react'; +import _ from 'lodash'; + +import {dispatch} from 'app/store'; +import i18n from 'lib-app/i18n'; + +import Menu from 'core-components/menu'; + +class AdminPanelMenu extends React.Component { + static contextTypes = { + router: React.PropTypes.object + }; + + static propTypes = { + location: React.PropTypes.object + }; + + render() { + return ( +
+ + +
+ ); + } + + getGroupsMenuProps() { + return { + items: this.getGroups(), + selectedIndex: this.getGroupIndex(), + onItemClick: this.onGroupClick.bind(this), + tabbable: true, + type: 'primary' + }; + } + + getGroupMenuProps() { + return { + items: this.getGroupItems(), + selectedIndex: this.getGroupItemIndex(), + onItemClick: this.onGroupItemClick.bind(this), + tabbable: true, + type: 'secondary' + }; + } + + getGroups() { + return this.getRoutes().map((group) => { + return { + content: group.groupName, + icon: group.icon + }; + }); + } + + getGroupItems() { + const group = this.getRoutes()[this.getGroupIndex()]; + + return group.items.map((item) => { + return { + content: item.name + }; + }); + } + + onGroupClick(index) { + this.context.router.push(this.getRoutes()[index].path); + } + + onGroupItemClick(index) { + const group = this.getRoutes()[this.getGroupIndex()]; + + this.context.router.push(group.items[index].path); + } + + getGroupItemIndex() { + const group = this.getRoutes()[this.getGroupIndex()]; + const pathname = this.props.location.pathname; + const itemIndex = _.findIndex(group.items, {path: pathname}); + + return (itemIndex === -1) ? 0 : itemIndex; + } + + getGroupIndex() { + const pathname = this.props.location.pathname; + const groupIndex = _.findLastIndex(this.getRoutes(), (group) => { + return _.includes(pathname, group.path); + }); + + return (groupIndex === -1) ? 0 : groupIndex; + } + + getRoutes() { + return [ + { + groupName: i18n('DASHBOARD'), + path: '/admin/panel', + icon: 'tachometer', + items: [ + { + name: i18n('TICKET_STATS'), + path: '/admin/panel/stats' + }, + { + name: i18n('LAST_ACTIVITY'), + path: '/admin/panel/activity' + } + ] + }, + { + groupName: i18n('TICKETS'), + path: '/admin/panel/tickets', + icon: 'ticket', + items: [ + { + name: i18n('MY_TICKETS'), + path: '/admin/panel/tickets/my-tickets' + }, + { + name: i18n('NEW_TICKETS'), + path: '/admin/panel/tickets/new-tickets' + }, + { + name: i18n('ALL_TICKETS'), + path: '/admin/panel/tickets/all-tickets' + }, + { + name: i18n('CUSTOM_RESPONSES'), + path: '/admin/panel/tickets/custom-responses' + } + ] + }, + { + groupName: i18n('USERS'), + path: '/admin/panel/users', + icon: 'user', + items: [ + { + name: i18n('LIST_USERS'), + path: '/admin/panel/users/list-users' + }, + { + name: i18n('BAN_USERS'), + path: '/admin/panel/users/ban-users' + } + ] + }, + { + groupName: i18n('ARTICLES'), + path: '/admin/panel/articles', + icon: 'book', + items: [ + { + name: i18n('LIST_ARTICLES'), + path: '/admin/panel/articles/list-articles' + } + ] + }, + { + + groupName: i18n('STAFF'), + path: '/admin/panel/staff', + icon: 'users', + items: [ + { + name: i18n('STAFF_MEMBERS'), + path: '/admin/panel/staff/staff-members' + }, + { + name: i18n('DEPARTMENTS'), + path: '/admin/panel/staff/departments' + } + ] + }, + { + + groupName: i18n('SETTINGS'), + path: '/admin/panel/settings', + icon: 'cogs', + items: [ + { + name: i18n('SYSTEM_PREFERENCES'), + path: '/admin/panel/settings/system-preferences' + }, + { + name: i18n('USER_SYSTEM'), + path: '/admin/panel/settings/user-system' + }, + { + name: i18n('EMAIL_TEMPLATES'), + path: '/admin/panel/settings/email-templates' + }, + { + name: i18n('FILTERS_CUSTOM_FIELDS'), + path: '/admin/panel/settings/custom-fields' + } + ] + } + ]; + } +} + +export default AdminPanelMenu; diff --git a/client/src/app/admin/panel/admin-panel-menu.scss b/client/src/app/admin/panel/admin-panel-menu.scss new file mode 100644 index 00000000..89d1a17b --- /dev/null +++ b/client/src/app/admin/panel/admin-panel-menu.scss @@ -0,0 +1,3 @@ +.admin-panel-menu { + +} \ No newline at end of file diff --git a/client/src/app/admin/panel/admin-panel-staff-widget.js b/client/src/app/admin/panel/admin-panel-staff-widget.js new file mode 100644 index 00000000..c213a752 --- /dev/null +++ b/client/src/app/admin/panel/admin-panel-staff-widget.js @@ -0,0 +1,47 @@ +import React from 'react'; +import classNames from 'classnames'; +import {connect} from 'react-redux'; + +import i18n from 'lib-app/i18n'; +import Button from 'core-components/button'; + +class AdminPanelStaffWidget extends React.Component { + + render() { + return ( +
+
+
{this.props.session.userName}
+
+ + | + +
+
+
+ +
+
+ ); + } + + getClass() { + let classes = { + 'admin-panel-staff-widget': true + }; + + classes[this.props.className] = (this.props.className); + + return classNames(classes); + } +} + +export default connect((store) => { + return { + session: store.session + }; +})(AdminPanelStaffWidget); diff --git a/client/src/app/admin/panel/admin-panel-staff-widget.scss b/client/src/app/admin/panel/admin-panel-staff-widget.scss new file mode 100644 index 00000000..1de336ad --- /dev/null +++ b/client/src/app/admin/panel/admin-panel-staff-widget.scss @@ -0,0 +1,47 @@ +@import '../../../scss/vars'; + +.admin-panel-staff-widget { + background-color: $secondary-blue; + position: relative; + width: 100%; + height: 165px; + text-align: center; + + &__profile-pic-wrapper { + position: absolute; + top: 8px; + border: 4px solid $grey; + border-radius: 50%; + width: 90px; + height: 90px; + overflow: hidden; + text-align: center; + left: 50%; + transform: translate(-50%, 0); + } + + &__profile-pic { + height: 100%; + position: absolute; + left: 50%; + transform: translate(-50%, 0); + } + + &__user-data { + position: absolute; + background-color: white; + bottom: 0; + width: 100%; + height: 110px; + padding-top: 48px; + } + + &__name { + font-size: $font-size--md; + } + + &__actions { + font-size: $font-size--xs; + margin-top: 10px; + } +} \ No newline at end of file diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 0eea85dc..c41e460c 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -36,6 +36,25 @@ export default { 'CUSTOMER': 'Customer', 'YES': 'Yes', 'CANCEL': 'Cancel', + 'MY_ACCOUNT': 'My Account', + 'DASHBOARD': 'Dashboard', + 'USERS': 'Users', + 'SETTINGS': 'Settings', + 'TICKET_STATS': 'Ticket Stats', + 'LAST_ACTIVITY': 'Last Activity', + 'MY_TICKETS': 'My Tickets', + 'NEW_TICKETS': 'New Tickets', + 'ALL_TICKETS': 'All Tickets', + 'CUSTOM_RESPONSES': 'Custom Responses', + 'LIST_USERS': 'List Users', + 'BAN_USERS': 'Ban Users', + 'LIST_ARTICLES': 'List Articles', + 'STAFF_MEMBERS': 'Staff Members', + 'DEPARTMENTS': 'Departments', + 'SYSTEM_PREFERENCES': 'System Preferences', + 'USER_SYSTEM': 'User System', + 'EMAIL_TEMPLATES': 'Email Templates', + 'FILTERS_CUSTOM_FIELDS': 'Filters and Custom Fields', //ERRORS 'EMAIL_NOT_EXIST': 'Email does not exist', From 116c974f9cbc83c9c6d00a2b06b69c906672a415 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 24 Sep 2016 21:33:09 -0300 Subject: [PATCH 06/14] Ivan - STAFF LOGIN - Add horizontal and horizontal-list menu [skip ci] --- .../src/app/admin/panel/admin-panel-menu.js | 7 +- client/src/app/demo/components-demo-page.js | 30 ++++-- client/src/core-components/menu.js | 4 +- client/src/core-components/menu.scss | 93 ++++++++++++++++++- 4 files changed, 122 insertions(+), 12 deletions(-) diff --git a/client/src/app/admin/panel/admin-panel-menu.js b/client/src/app/admin/panel/admin-panel-menu.js index de97eaf4..5f77ef37 100644 --- a/client/src/app/admin/panel/admin-panel-menu.js +++ b/client/src/app/admin/panel/admin-panel-menu.js @@ -30,7 +30,7 @@ class AdminPanelMenu extends React.Component { selectedIndex: this.getGroupIndex(), onItemClick: this.onGroupClick.bind(this), tabbable: true, - type: 'primary' + type: 'horizontal' }; } @@ -40,7 +40,7 @@ class AdminPanelMenu extends React.Component { selectedIndex: this.getGroupItemIndex(), onItemClick: this.onGroupItemClick.bind(this), tabbable: true, - type: 'secondary' + type: 'horizontal-list' }; } @@ -76,9 +76,8 @@ class AdminPanelMenu extends React.Component { getGroupItemIndex() { const group = this.getRoutes()[this.getGroupIndex()]; const pathname = this.props.location.pathname; - const itemIndex = _.findIndex(group.items, {path: pathname}); - return (itemIndex === -1) ? 0 : itemIndex; + return _.findIndex(group.items, {path: pathname}); } getGroupIndex() { diff --git a/client/src/app/demo/components-demo-page.js b/client/src/app/demo/components-demo-page.js index 363d4873..122bff4a 100644 --- a/client/src/app/demo/components-demo-page.js +++ b/client/src/app/demo/components-demo-page.js @@ -65,12 +65,6 @@ let DemoPage = React.createClass({ ) }, - { - title: 'DropDown', - render: ( - - ) - }, { title: 'Primary Menu', render: ( @@ -83,6 +77,30 @@ let DemoPage = React.createClass({ ) }, + { + title: 'Navigation Menu', + render: ( + + ) + }, + { + title: 'Horizontal Menu', + render: ( + + ) + }, + { + title: 'HorizontalList Menu', + render: ( + + ) + }, + { + title: 'DropDown', + render: ( + + ) + }, { title: 'Tooltip', render: ( diff --git a/client/src/core-components/menu.js b/client/src/core-components/menu.js index 18158405..3a7d849f 100644 --- a/client/src/core-components/menu.js +++ b/client/src/core-components/menu.js @@ -84,7 +84,9 @@ class Menu extends React.Component { let classes = { 'menu': true, 'menu_secondary': (this.props.type === 'secondary'), - 'menu_navigation': (this.props.type === 'navigation') + 'menu_navigation': (this.props.type === 'navigation'), + 'menu_horizontal': (this.props.type === 'horizontal'), + 'menu_horizontal-list': (this.props.type === 'horizontal-list') }; classes[this.props.className] = true; diff --git a/client/src/core-components/menu.scss b/client/src/core-components/menu.scss index ab2c661b..3a425f87 100644 --- a/client/src/core-components/menu.scss +++ b/client/src/core-components/menu.scss @@ -1,5 +1,7 @@ @import "../scss/vars"; +$transition: background-color 0.3s ease, color 0.3s ease; + .menu { &__list { @@ -13,7 +15,7 @@ &__list-item { padding: 8px; - transition: background-color 0.3s ease, color 0.3s ease; + transition: $transition; &_selected, &:hover { @@ -78,4 +80,93 @@ color: $primary-blue; } } + + &_horizontal { + text-align: center; + + .menu__list { + background-color: transparent; + font-size: $font-size--md; + } + + .menu__icon { + display: block; + margin-right: 0; + margin-bottom: 20px; + margin-top: 20px; + font-size: $font-size--xl; + } + + .menu__list-item { + background-color: white; + color: $primary-black; + cursor: pointer; + display: inline-block; + height: 120px; + width: 16.6667%; + + @media (max-width: 667px) { + width: 33.3333%; + } + } + + .menu__list-item_selected { + background-color: $secondary-blue; + color: white; + } + + .menu__list-item:hover, + .menu__list-item:focus { + color: $dark-grey; + outline: none; + } + + .menu__list-item_selected:focus, + .menu__list-item_selected:hover { + color: white; + } + } + + &_horizontal-list { + text-align: left; + background-color: $secondary-blue; + min-height: 45px; + + .menu__list { + background-color: transparent; + font-size: $font-size--sm; + } + + .menu__list-item { + transition: none; + background-color: transparent; + color: white; + cursor: pointer; + display: inline-block; + margin-top: 11px; + margin-bottom: 10px; + margin-left: 20px; + padding: 2px 13px; + } + + .menu__list-item:hover { + transition: $transition; + background-color: transparent; + color: $primary-black; + } + + .menu__list-item:focus { + color: $grey; + outline: none; + } + + .menu__list-item_selected, + .menu__list-item_selected:hover { + transition: $transition; + padding: 2px 13px; + border-radius: 30px; + background-color: $primary-blue; + color: white; + } + } } \ No newline at end of file From cc7c5bfb3da689f690d16a6ef4dc4621325b9c66 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 25 Sep 2016 01:16:10 -0300 Subject: [PATCH 07/14] Ivan - STAFF LOGIN - Add Staff login to backend [skip ci] --- server/controllers/staff.php | 9 ++++++ server/controllers/staff/get.php | 36 +++++++++++++++++++++ server/controllers/user/get.php | 5 +++ server/controllers/user/login.php | 9 ++++-- server/libs/Controller.php | 16 +++++---- server/libs/Validator.php | 5 +-- server/models/Session.php | 7 +++- server/models/Staff.php | 5 +++ server/models/User.php | 5 +-- server/tests/controllers/user/loginTest.php | 3 +- tests/init.rb | 1 + tests/libs.rb | 5 +++ tests/scripts.rb | 5 +-- tests/staff/get.rb | 15 +++++++++ tests/user/login.rb | 33 ++++++++++++++++--- tests/user/signup.rb | 1 - 16 files changed, 135 insertions(+), 25 deletions(-) create mode 100644 server/controllers/staff.php create mode 100644 server/controllers/staff/get.php create mode 100644 tests/staff/get.rb diff --git a/server/controllers/staff.php b/server/controllers/staff.php new file mode 100644 index 00000000..21df1a90 --- /dev/null +++ b/server/controllers/staff.php @@ -0,0 +1,9 @@ +setGroupPath('/staff'); + +$systemControllerGroup->addController(new GetStaffController); + +$systemControllerGroup->finalize(); \ No newline at end of file diff --git a/server/controllers/staff/get.php b/server/controllers/staff/get.php new file mode 100644 index 00000000..db922c80 --- /dev/null +++ b/server/controllers/staff/get.php @@ -0,0 +1,36 @@ + 'staff_1', + 'requestData' => [] + ]; + } + + public function handler() { + $user = Controller::getLoggedUser(); + $parsedDepartmentList = []; + $departmentList = $user->sharedDepartmentList; + + foreach($departmentList as $department) { + $parsedDepartmentList[] = [ + 'id' => $department->id, + 'name' => $department->name + ]; + } + + Response::respondSuccess([ + 'name' => $user->name, + 'email' => $user->email, + 'profilePic' => $user->profilePic, + 'level' => $user->level, + 'staff' => true, + 'departments' => $parsedDepartmentList + ]); + } +} \ No newline at end of file diff --git a/server/controllers/user/get.php b/server/controllers/user/get.php index 9310c5cf..23aa331e 100644 --- a/server/controllers/user/get.php +++ b/server/controllers/user/get.php @@ -13,6 +13,11 @@ class GetUserController extends Controller { } public function handler() { + if (Controller::isStaffLogged()) { + Response::respondError(ERRORS::INVALID_CREDENTIALS); + return; + } + $user = Controller::getLoggedUser(); $parsedTicketList = []; $ticketList = $user->sharedTicketList; diff --git a/server/controllers/user/login.php b/server/controllers/user/login.php index b32e757e..07cb3340 100644 --- a/server/controllers/user/login.php +++ b/server/controllers/user/login.php @@ -46,7 +46,7 @@ class LoginController extends Controller { } private function createUserSession() { - Session::getInstance()->createSession($this->userInstance->id); + Session::getInstance()->createSession($this->userInstance->id, Controller::request('staff')); } private function getUserData() { @@ -55,6 +55,7 @@ class LoginController extends Controller { return array( 'userId' => $userInstance->id, 'userEmail' => $userInstance->email, + 'staff' => Controller::request('staff'), 'token' => Session::getInstance()->getToken(), 'rememberToken' => $this->rememberToken ); @@ -64,7 +65,11 @@ class LoginController extends Controller { $email = Controller::request('email'); $password = Controller::request('password'); - return User::authenticate($email, $password); + if(Controller::request('staff')) { + return Staff::authenticate($email, $password); + } else { + return User::authenticate($email, $password); + } } private function getUserByRememberToken() { diff --git a/server/libs/Controller.php b/server/libs/Controller.php index 73a642b2..8403f7c5 100644 --- a/server/libs/Controller.php +++ b/server/libs/Controller.php @@ -36,7 +36,13 @@ abstract class Controller { } public static function getLoggedUser() { - return User::getUser((int)self::request('csrf_userid')); + $session = Session::getInstance(); + + if ($session->isStaffLogged()) { + return Staff::getUser((int)self::request('csrf_userid')); + } else { + return User::getUser((int)self::request('csrf_userid')); + } } public static function isUserLogged() { @@ -48,12 +54,8 @@ abstract class Controller { )); } - public static function isStaffLogged() { - return Controller::isUserLogged() && (Controller::getLoggedUser()->admin === 1); - } - - public static function isAdminLogged() { - return Controller::isUserLogged() && (Controller::getLoggedUser()->admin === 2); + public static function isStaffLogged($level = 1) { + return Controller::isUserLogged() && (Controller::getLoggedUser()->level >= $level); } public static function getAppInstance() { diff --git a/server/libs/Validator.php b/server/libs/Validator.php index 7bf85acc..a3c19a98 100644 --- a/server/libs/Validator.php +++ b/server/libs/Validator.php @@ -16,8 +16,9 @@ class Validator { $permissions = [ 'any' => true, 'user' => Controller::isUserLogged(), - 'staff' => Controller::isStaffLogged(), - 'admin' => Controller::isAdminLogged() + 'staff_1' => Controller::isStaffLogged(1), + 'staff_2' => Controller::isStaffLogged(2), + 'staff_3' => Controller::isStaffLogged(3) ]; if (!$permissions[$permission]) { diff --git a/server/models/Session.php b/server/models/Session.php index 9bb54dd6..9535876a 100644 --- a/server/models/Session.php +++ b/server/models/Session.php @@ -24,8 +24,9 @@ class Session { return self::$instance; } - public function createSession($userId) { + public function createSession($userId, $staff = false) { $this->store('userId', $userId); + $this->store('staff', $staff); $this->store('token', Hashing::generateRandomToken()); } @@ -37,6 +38,10 @@ class Session { return !!$this->getToken(); } + public function isStaffLogged() { + return $this->getStoredData('staff'); + } + public function checkAuthentication($data) { $userId = $this->getStoredData('userId'); $token = $this->getStoredData('token'); diff --git a/server/models/Staff.php b/server/models/Staff.php index 1f5b7084..03e3e078 100644 --- a/server/models/Staff.php +++ b/server/models/Staff.php @@ -3,6 +3,11 @@ class Staff extends DataStore { const TABLE = 'staff'; + public static function authenticate($userEmail, $userPassword) { + $user = Staff::getUser($userEmail, 'email'); + + return ($user && Hashing::verifyPassword($userPassword, $user->password)) ? $user : new NullDataStore(); + } public static function getProps() { return [ diff --git a/server/models/User.php b/server/models/User.php index eefbc4c5..b25f5a1a 100644 --- a/server/models/User.php +++ b/server/models/User.php @@ -15,16 +15,13 @@ class User extends DataStore { 'email', 'password', 'name', - 'admin', 'sharedTicketList', 'verificationToken', ]; } public function getDefaultProps() { - return [ - 'admin' => 0 - ]; + return []; } public static function getUser($value, $property = 'id') { diff --git a/server/tests/controllers/user/loginTest.php b/server/tests/controllers/user/loginTest.php index 0f78bc03..2a1583f7 100644 --- a/server/tests/controllers/user/loginTest.php +++ b/server/tests/controllers/user/loginTest.php @@ -35,10 +35,11 @@ class LoginControllerTest extends PHPUnit_Framework_TestCase { $this->loginController->handler(); - $this->assertTrue(Session::getInstance()->createSession->hasBeenCalledWithArgs('MOCK_ID')); + $this->assertTrue(Session::getInstance()->createSession->hasBeenCalledWithArgs('MOCK_ID', null)); $this->assertTrue(Response::get('respondSuccess')->hasBeenCalledWithArgs(array( 'userId' => 'MOCK_ID', 'userEmail' => 'MOCK_EMAIL', + 'staff' => null, 'token' => 'TEST_TOKEN', 'rememberToken' => null ))); diff --git a/tests/init.rb b/tests/init.rb index fb875785..db0b6d11 100644 --- a/tests/init.rb +++ b/tests/init.rb @@ -21,3 +21,4 @@ require './user/get.rb' require './ticket/create.rb' require './ticket/comment.rb' require './ticket/get.rb' +require './staff/get.rb' diff --git a/tests/libs.rb b/tests/libs.rb index 907ef709..b8431702 100644 --- a/tests/libs.rb +++ b/tests/libs.rb @@ -26,3 +26,8 @@ class Database end $database = Database.new + +$staff = { + :email => 'staff@opensupports.com', + :password => 'staff' +} diff --git a/tests/scripts.rb b/tests/scripts.rb index f6b3e18d..6b91569e 100644 --- a/tests/scripts.rb +++ b/tests/scripts.rb @@ -11,11 +11,12 @@ class Scripts end end - def self.login(email = 'steve@jobs.com', password = 'custompassword') + def self.login(email = 'steve@jobs.com', password = 'custompassword', staff = false) request('/user/logout') response = request('/user/login', { :email => email, - :password => password + :password => password, + :staff => staff }) if response['data'].any? diff --git a/tests/staff/get.rb b/tests/staff/get.rb new file mode 100644 index 00000000..a0abd11b --- /dev/null +++ b/tests/staff/get.rb @@ -0,0 +1,15 @@ +describe '/staff/get/' do + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) + + it 'should return staff member data' do + result = request('/staff/get', { + csrf_userid: $csrf_userid, + csrf_token: $csrf_token + }) + + (result['status']).should.equal('success') + (result['data']['name']).should.equal('Emilia Clarke') + (result['data']['staff']).should.equal(true) + end +end \ No newline at end of file diff --git a/tests/user/login.rb b/tests/user/login.rb index 7c0d5738..870cbc1f 100644 --- a/tests/user/login.rb +++ b/tests/user/login.rb @@ -13,13 +13,36 @@ describe '/user/login' do (result['status']).should.equal('fail') end -# it 'should login correctly' do + it 'should login correctly' do + result = request('/user/login', { + email: @loginEmail, + password: @loginPass + }) -# end + (result['status']).should.equal('success') + end -# it 'should fail if already logged in' do + it 'should fail if already logged in' do + result = request('/user/login', { + email: @loginEmail, + password: @loginPass + }) -# end + (result['status']).should.equal('fail') + (result['message']).should.equal('User is already logged in') + end + + it 'should login staff member' do + request('/user/logout', {}) + result = request('/user/login', { + email: $staff[:email], + password: $staff[:password], + staff: true + }) + + (result['status']).should.equal('success') + (result['data']['staff']).should.equal('true') + end it 'should return remember token' do request('/user/logout', {}) @@ -31,7 +54,7 @@ describe '/user/login' do (result['status']).should.equal('success') - @rememberToken = result['data']['rememberToken']# falta comproversion + @rememberToken = result['data']['rememberToken'] @userid = result['data']['userId'] end diff --git a/tests/user/signup.rb b/tests/user/signup.rb index f1309ddc..bebf131d 100644 --- a/tests/user/signup.rb +++ b/tests/user/signup.rb @@ -10,7 +10,6 @@ describe '/user/signup' do (userRow['email']).should.equal('steve@jobs.com') (userRow['name']).should.equal('Steve Jobs') - (userRow['admin']).should.equal('0') end it 'should fail if name is invalid' do From 842afe49eb4edd6d2ddb7ec761696bb39249dbc5 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 25 Sep 2016 01:30:38 -0300 Subject: [PATCH 08/14] Ivan - STAFF LOGIN - Fix issues and improve frontend login [skip ci] --- client/src/app/App.js | 2 +- client/src/app/admin/admin-login-page.js | 21 +++++++++++++++++-- client/src/app/admin/admin-login-page.scss | 8 +++---- .../admin/panel/admin-panel-staff-widget.js | 7 ++++++- .../dashboard-edit-profile-page.js | 1 - client/src/data/languages/en.js | 1 + 6 files changed, 31 insertions(+), 9 deletions(-) diff --git a/client/src/app/App.js b/client/src/app/App.js index 90197430..52d55cb5 100644 --- a/client/src/app/App.js +++ b/client/src/app/App.js @@ -45,7 +45,7 @@ class App extends React.Component { languageChanged: props.config.language !== this.props.config.language, loggedIn: !_.includes(props.location.pathname, '/dashboard') && props.session.logged, loggedOut: _.includes(props.location.pathname, '/dashboard') && !props.session.logged, - loggedInStaff: !_.includes(props.location.pathname, '/admin/panel') && props.session.staff, + loggedInStaff: !_.includes(props.location.pathname, '/admin/panel') && props.session.logged && props.session.staff, loggedOutStaff: _.includes(props.location.pathname, '/admin/panel') && !props.session.logged }; diff --git a/client/src/app/admin/admin-login-page.js b/client/src/app/admin/admin-login-page.js index 12d74dc5..9d7f2770 100644 --- a/client/src/app/admin/admin-login-page.js +++ b/client/src/app/admin/admin-login-page.js @@ -8,12 +8,14 @@ import SessionActions from 'actions/session-actions'; import Form from 'core-components/form'; import FormField from 'core-components/form-field'; import SubmitButton from 'core-components/submit-button'; +import Message from 'core-components/message'; +import Widget from 'core-components/widget'; class AdminLoginPage extends React.Component { render() { return (
-
+
OpenSupports Admin Panel
@@ -22,11 +24,26 @@ class AdminLoginPage extends React.Component { {i18n('LOG_IN')}
-
+ {this.renderMessage()} +
); } + renderMessage() { + let message = null; + + if(this.props.session.failed) { + message = ( + + {i18n('EMAIL_OR_PASSWORD')} + + ); + } + + return message; + } + onSubmit(formState) { this.props.dispatch(SessionActions.login(_.extend({}, formState, { staff: true diff --git a/client/src/app/admin/admin-login-page.scss b/client/src/app/admin/admin-login-page.scss index 60a5a738..57b07631 100644 --- a/client/src/app/admin/admin-login-page.scss +++ b/client/src/app/admin/admin-login-page.scss @@ -5,11 +5,7 @@ &__content { margin: 0 auto; - display: inline-block; - background-color: white; padding: 40px; - border-radius: 4px; - text-align: center; } &__image { @@ -21,4 +17,8 @@ margin: 0 auto; display: inline-block; } + + &__error { + margin-top: 30px; + } } \ No newline at end of file diff --git a/client/src/app/admin/panel/admin-panel-staff-widget.js b/client/src/app/admin/panel/admin-panel-staff-widget.js index c213a752..913f151d 100644 --- a/client/src/app/admin/panel/admin-panel-staff-widget.js +++ b/client/src/app/admin/panel/admin-panel-staff-widget.js @@ -4,6 +4,7 @@ import {connect} from 'react-redux'; import i18n from 'lib-app/i18n'; import Button from 'core-components/button'; +import SessionActions from 'actions/session-actions'; class AdminPanelStaffWidget extends React.Component { @@ -17,7 +18,7 @@ class AdminPanelStaffWidget extends React.Component { {i18n('MY_ACCOUNT')} | -
@@ -38,6 +39,10 @@ class AdminPanelStaffWidget extends React.Component { return classNames(classes); } + + closeSession() { + this.props.dispatch(SessionActions.logout()); + } } export default connect((store) => { diff --git a/client/src/app/main/dashboard/dashboard-edit-profile/dashboard-edit-profile-page.js b/client/src/app/main/dashboard/dashboard-edit-profile/dashboard-edit-profile-page.js index 4e32405f..fed82146 100644 --- a/client/src/app/main/dashboard/dashboard-edit-profile/dashboard-edit-profile-page.js +++ b/client/src/app/main/dashboard/dashboard-edit-profile/dashboard-edit-profile-page.js @@ -20,7 +20,6 @@ class DashboardEditProfilePage extends React.Component { messagePass:'' }; - render() { return (
diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index c41e460c..8335a733 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -57,6 +57,7 @@ export default { 'FILTERS_CUSTOM_FIELDS': 'Filters and Custom Fields', //ERRORS + 'EMAIL_OR_PASSWORD': 'Email or password invalid', 'EMAIL_NOT_EXIST': 'Email does not exist', 'ERROR_EMPTY': 'Invalid value', 'ERROR_PASSWORD': 'Invalid password', From 0bed4bef4502090128d4a41a03a46a5c2e1d23c4 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 29 Sep 2016 14:34:20 -0300 Subject: [PATCH 09/14] Ivan - Add events to backend [skip ci] --- server/controllers/ticket/comment.php | 11 +++-- server/data/ERRORS.php | 1 + server/models/Ticket.php | 43 +++++++++++-------- server/models/Ticketevent.php | 60 +++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 21 deletions(-) create mode 100644 server/models/Ticketevent.php diff --git a/server/controllers/ticket/comment.php b/server/controllers/ticket/comment.php index bc3e4a91..cbf077ed 100644 --- a/server/controllers/ticket/comment.php +++ b/server/controllers/ticket/comment.php @@ -44,14 +44,19 @@ class CommentController extends Controller { } private function storeComment() { - $comment = new Comment(); + $comment = Ticketevent::getEvent(Ticketevent::COMMENT); $comment->setProperties(array( 'content' => $this->content, - 'author' => Controller::getLoggedUser(), 'date' => Date::getCurrentDate() )); - $this->ticket->ownCommentList->add($comment); + if(Controller::isStaffLogged()) { + $comment->authorUser = Controller::getLoggedUser(); + } else { + $comment->authorUser = Controller::getLoggedUser(); + } + + $this->ticket->ownTicketeventList->add($comment); $this->ticket->store(); } } \ No newline at end of file diff --git a/server/data/ERRORS.php b/server/data/ERRORS.php index 2e627cb9..d173ccfa 100644 --- a/server/data/ERRORS.php +++ b/server/data/ERRORS.php @@ -15,4 +15,5 @@ class ERRORS { const INIT_SETTINGS_DONE = 'Settings already initialized'; const INVALID_OLD_PASSWORD = 'Invalid old password'; const INVALID_CAPTCHA = 'Invalid captcha'; + const INVALID_TICKET_EVENT = 'INVALID_TICKET_EVENT'; } diff --git a/server/models/Ticket.php b/server/models/Ticket.php index 8de49c28..808d36fd 100644 --- a/server/models/Ticket.php +++ b/server/models/Ticket.php @@ -17,7 +17,7 @@ class Ticket extends DataStore { 'closed', 'author', 'owner', - 'ownCommentList' + 'ownTicketeventList' ); } @@ -39,6 +39,7 @@ class Ticket extends DataStore { public function store() { parent::store(); } + public function generateUniqueTicketNumber() { $ticketQuantity = Ticket::count('ticket'); $minValue = 100000; @@ -57,8 +58,6 @@ class Ticket extends DataStore { } public function toArray() { - $author = $this->author; - return [ 'ticketNumber' => $this->ticketNumber, 'title' => $this->title, @@ -74,7 +73,7 @@ class Ticket extends DataStore { 'closed' => !!$this->closed, 'author' => $this->authorToArray(), 'owner' => $this->ownerToArray(), - 'comments' => $this->commentsToArray() + 'events' => $this->eventsToArray() ]; } @@ -106,23 +105,31 @@ class Ticket extends DataStore { } } - public function commentsToArray() { - $comments = []; + public function eventsToArray() { + $events = []; - foreach ($this->ownCommentList as $comment) { - $comments[] = [ - 'content'=> $comment->content, - 'author' => [ - 'id'=> 15, - 'name' => $comment->author->name, - 'email' => $comment->author->email, - 'staff' => $comment->author->staff - ], - 'date'=> $comment->date, - 'file'=> $comment->file + foreach ($this->ownTicketeventList as $ticketEvent) { + $event = [ + 'type' => $ticketEvent->type, + 'content'=> $ticketEvent->content, + 'author' => [], + 'date'=> $ticketEvent->date, + 'file'=> $ticketEvent->file ]; + + $author = $ticketEvent->getAuthor(); + if(!$author->isNull()) { + $event['author'] = [ + 'id'=> $author->id, + 'name' => $author->name, + 'email' =>$author->email, + 'staff' => $author instanceof Staff + ]; + } + + $events[] = $event; } - return $comments; + return $events; } } diff --git a/server/models/Ticketevent.php b/server/models/Ticketevent.php new file mode 100644 index 00000000..81bab0c0 --- /dev/null +++ b/server/models/Ticketevent.php @@ -0,0 +1,60 @@ +setProperties([ + 'type' => $type + ]); + + return $ticketEvent; + } + + public function getProps() { + return [ + 'type', + 'content', + 'file', + 'authorUser', + 'authorStaff', + 'date' + ]; + } + + public function getAuthor() { + if($this->authorUser) { + return $this->authorUser; + } + + if($this->authorStaff) { + return $this->authorStaff; + } + + return new NullDataStore(); + } +} \ No newline at end of file From 34d8e9702b7bcba7bfc4d11150d7b75612197ce9 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 29 Sep 2016 14:41:59 -0300 Subject: [PATCH 10/14] Ivan - Update comment tests [skip ci] --- tests/ticket/comment.rb | 5 +++-- tests/ticket/get.rb | 12 +++++++++++- tests/user/get.rb | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/tests/ticket/comment.rb b/tests/ticket/comment.rb index 3d21d6e6..422c2244 100644 --- a/tests/ticket/comment.rb +++ b/tests/ticket/comment.rb @@ -68,9 +68,10 @@ describe '/ticket/comment/' do (result['status']).should.equal('success') ticket = $database.getRow('ticket', @ticketNumber, 'ticket_number') - comment = $database.getRow('comment', ticket['id'], 'ticket_id') + comment = $database.getRow('ticketevent', ticket['id'], 'ticket_id') (comment['content']).should.equal('some comment content') - (comment['author_id']).should.equal($csrf_userid) + (comment['type']).should.equal('COMMENT') + (comment['author_user_id']).should.equal($csrf_userid) end it 'should fail if user is not the author nor owner' do diff --git a/tests/ticket/get.rb b/tests/ticket/get.rb index 8cb77ad4..698192f7 100644 --- a/tests/ticket/get.rb +++ b/tests/ticket/get.rb @@ -15,6 +15,13 @@ describe '/ticket/get/' do csrf_token: $csrf_token }) @ticketNumber = result['data']['ticketNumber'] + + request('/ticket/comment', { + ticketNumber: @ticketNumber, + content: 'some valid comment made', + csrf_userid: $csrf_userid, + csrf_token: $csrf_token + }) end it 'should fail if ticketNumber is invalid' do @@ -46,6 +53,7 @@ describe '/ticket/get/' do result = Scripts.login('cersei@os4.com', 'cersei') $csrf_userid = result['userId'] $csrf_token = result['token'] + result = request('/ticket/get', { ticketNumber: @ticketNumber, csrf_userid: $csrf_userid, @@ -68,6 +76,8 @@ describe '/ticket/get/' do (result['data']['author']['name']).should.equal('Cersei Lannister') (result['data']['author']['email']).should.equal('cersei@os4.com') (result['data']['owner']).should.equal([]) - (result['data']['comments']).should.equal([]) + (result['data']['events'].size).should.equal(1) + (result['data']['events'][0]['type']).should.equal('COMMENT') + (result['data']['events'][0]['content']).should.equal('some valid comment made') end end \ No newline at end of file diff --git a/tests/user/get.rb b/tests/user/get.rb index 543404a8..bf142ffe 100644 --- a/tests/user/get.rb +++ b/tests/user/get.rb @@ -52,6 +52,6 @@ describe '/user/get' do (ticketFromUser['author']['name']).should.equal('User Get') (ticketFromUser['author']['email']).should.equal('user_get@os4.com') (ticketFromUser['owner']).should.equal([]) - (ticketFromUser['comments']).should.equal([]) + (ticketFromUser['events']).should.equal([]) end end \ No newline at end of file From 4512d4b484a9bb7c92c00e4ee146f6ff2bfaf09a Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 29 Sep 2016 14:46:31 -0300 Subject: [PATCH 11/14] Ivan - Create Ticket::addEvent function [skip ci] --- server/controllers/ticket/comment.php | 2 +- server/models/Ticket.php | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/server/controllers/ticket/comment.php b/server/controllers/ticket/comment.php index cbf077ed..83fb5513 100644 --- a/server/controllers/ticket/comment.php +++ b/server/controllers/ticket/comment.php @@ -56,7 +56,7 @@ class CommentController extends Controller { $comment->authorUser = Controller::getLoggedUser(); } - $this->ticket->ownTicketeventList->add($comment); + $this->ticket->addEvent($comment); $this->ticket->store(); } } \ No newline at end of file diff --git a/server/models/Ticket.php b/server/models/Ticket.php index 808d36fd..b2c73b2d 100644 --- a/server/models/Ticket.php +++ b/server/models/Ticket.php @@ -132,4 +132,8 @@ class Ticket extends DataStore { return $events; } + + public function addEvent(Ticketevent $event) { + $this->ownTicketeventList->add($event); + } } From 6ee9e412c100c468a8b4a9acd4056cf4f68322e2 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 29 Sep 2016 14:47:25 -0300 Subject: [PATCH 12/14] Ivan - Eliminate Comment DataStore [skip ci] --- server/models/Comment.php | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 server/models/Comment.php diff --git a/server/models/Comment.php b/server/models/Comment.php deleted file mode 100644 index 1ff8ae86..00000000 --- a/server/models/Comment.php +++ /dev/null @@ -1,14 +0,0 @@ - Date: Thu, 29 Sep 2016 17:09:34 -0300 Subject: [PATCH 13/14] antonyantonio - add priority ticket backend[skip ci] --- server/models/Ticket.php | 3 +++ tests/ticket/create.rb | 1 + 2 files changed, 4 insertions(+) diff --git a/server/models/Ticket.php b/server/models/Ticket.php index b2c73b2d..03e22fc7 100644 --- a/server/models/Ticket.php +++ b/server/models/Ticket.php @@ -15,6 +15,7 @@ class Ticket extends DataStore { 'date', 'unread', 'closed', + 'priority', 'author', 'owner', 'ownTicketeventList' @@ -32,6 +33,7 @@ class Ticket extends DataStore { public function getDefaultProps() { return array( 'owner' => null, + 'priority' => 'low', 'ticketNumber' => $this->generateUniqueTicketNumber() ); } @@ -71,6 +73,7 @@ class Ticket extends DataStore { 'language' => $this->language, 'unread' => !!$this->unread, 'closed' => !!$this->closed, + 'priority' => $this->priority, 'author' => $this->authorToArray(), 'owner' => $this->ownerToArray(), 'events' => $this->eventsToArray() diff --git a/tests/ticket/create.rb b/tests/ticket/create.rb index f5367232..9bde8203 100644 --- a/tests/ticket/create.rb +++ b/tests/ticket/create.rb @@ -100,6 +100,7 @@ describe '/ticket/create' do (ticket['content']).should.equal('The north remembers') (ticket['unread']).should.equal('0') (ticket['closed']).should.equal('0') + (ticket['priority']).should.equal('low') (ticket['department_id']).should.equal('1') (ticket['author_id']).should.equal($csrf_userid) (ticket['ticket_number'].size).should.equal(6) From bbb1fe6111e472a217ad7844de6b024f5f924180 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 29 Sep 2016 18:27:16 -0300 Subject: [PATCH 14/14] antonyantonio - add priority ticket backend[skip ci] --- client/src/app-components/ticket-list.js | 136 ++++++++++++++++++ client/src/app-components/tiket-list.scss | 47 ++++++ .../dashboard-list-tickets-page.js | 55 +------ .../dashboard-list-tickets-page.scss | 26 ---- client/src/data/fixtures/user-fixtures.js | 42 ++++++ client/src/data/languages/en.js | 6 + 6 files changed, 233 insertions(+), 79 deletions(-) create mode 100644 client/src/app-components/ticket-list.js create mode 100644 client/src/app-components/tiket-list.scss delete mode 100644 client/src/app/main/dashboard/dashboard-list-tickets/dashboard-list-tickets-page.scss diff --git a/client/src/app-components/ticket-list.js b/client/src/app-components/ticket-list.js new file mode 100644 index 00000000..6bf7f885 --- /dev/null +++ b/client/src/app-components/ticket-list.js @@ -0,0 +1,136 @@ +import React from 'react'; + +import i18n from 'lib-app/i18n'; + +import Table from 'core-components/table'; +import Button from 'core-components/button'; +import Tooltip from 'core-components/tooltip'; + +class TicketList extends React.Component { + static propTypes = { + tickets: React.PropTypes.arrayOf(React.PropTypes.object), + type: React.PropTypes.oneOf([ + 'primary', + 'secondary' + ]) + }; + + static defaultProps = { + tickets: [], + type: 'primary' + }; + + render() { + return ( +
+ + + ); + } + + getTableHeaders() { + if (this.props.type == 'primary' ) { + return [ + { + key: 'number', + value: i18n('NUMBER'), + className: 'ticket-list__number col-md-1' + }, + { + key: 'title', + value: i18n('TITLE'), + className: 'ticket-list__title col-md-6' + }, + { + key: 'department', + value: i18n('DEPARTMENT'), + className: 'ticket-list__department col-md-3' + }, + { + key: 'date', + value: i18n('DATE'), + className: 'ticket-list__date col-md-2' + } + ]; + } else if (this.props.type == 'secondary') { + return [ + { + key: 'number', + value: i18n('NUMBER'), + className: 'ticket-list__number col-md-1' + }, + { + key: 'title', + value: i18n('TITLE'), + className: 'ticket-list__title col-md-4' + }, + { + key: 'priority', + value: i18n('PRIORITY'), + className: 'ticket-list__priority col-md-1' + }, + { + key: 'department', + value: i18n('DEPARTMENT'), + className: 'ticket-list__department col-md-2' + }, + { + key: 'author', + value: i18n('AUTHOR'), + className: 'ticket-list__author col-md-2' + }, + { + key: 'date', + value: i18n('DATE'), + className: 'ticket-list__date col-md-2' + } + ]; + } + } + + getTableRows() { + return this.props.tickets.map(this.gerTicketTableObject.bind(this)); + } + + gerTicketTableObject(ticket) { + let titleText = (ticket.unread) ? ticket.title + ' (1)' : ticket.title; + + return { + number: ( + + {'#' + ticket.ticketNumber} + + ), + title: ( + + ), + priority: this.getTicketPriority(ticket.priority), + department: ticket.department.name, + author: ticket.author.name, + date: ticket.date, + highlighted: ticket.unread + }; + } + getTicketPriority(priority){ + if(priority == 'high'){ + return ( + {i18n('HIGH')} + ); + } + if(priority == 'medium'){ + return ( + {i18n('MEDIUM')} + ); + } + if(priority == 'low'){ + return ( + {i18n('LOW')} + ); + } + } +} + + +export default TicketList; diff --git a/client/src/app-components/tiket-list.scss b/client/src/app-components/tiket-list.scss new file mode 100644 index 00000000..2355c6e4 --- /dev/null +++ b/client/src/app-components/tiket-list.scss @@ -0,0 +1,47 @@ +@import "../scss/vars"; + +.ticket-list { + + &__number { + text-align: left; + } + + &__title { + text-align: left; + } + + &__department { + text-align: right; + } + + &__date { + text-align: right; + } + + &__title-link:hover, + &__title-link:focus { + outline: none; + text-decoration: underline; + } + + &__priority-low, + &__priority-medium, + &__priority-high { + display: inline-block; + border-radius: 10px; + width: 70px; + color: white; + } + + &__priority-low { + background-color: $primary-green; + } + + &__priority-medium { + background-color: $secondary-blue; + } + + &__priority-high { + background-color: $primary-red; + } +} \ No newline at end of file diff --git a/client/src/app/main/dashboard/dashboard-list-tickets/dashboard-list-tickets-page.js b/client/src/app/main/dashboard/dashboard-list-tickets/dashboard-list-tickets-page.js index 40707fa8..1623df49 100644 --- a/client/src/app/main/dashboard/dashboard-list-tickets/dashboard-list-tickets-page.js +++ b/client/src/app/main/dashboard/dashboard-list-tickets/dashboard-list-tickets-page.js @@ -4,9 +4,7 @@ import {connect} from 'react-redux'; import i18n from 'lib-app/i18n'; import Header from 'core-components/header'; -import Table from 'core-components/table'; -import Button from 'core-components/button'; -import Tooltip from 'core-components/tooltip'; +import TicketList from 'app-components/ticket-list'; class DashboardListTicketsPage extends React.Component { static propTypes = { @@ -21,59 +19,10 @@ class DashboardListTicketsPage extends React.Component { return (
-
+ ); } - - getTableHeaders() { - return [ - { - key: 'number', - value: 'Number', - className: 'dashboard-ticket-list__number col-md-1' - }, - { - key: 'title', - value: 'Title', - className: 'dashboard-ticket-list__title col-md-6' - }, - { - key: 'department', - value: 'Department', - className: 'dashboard-ticket-list__department col-md-3' - }, - { - key: 'date', - value: 'Date', - className: 'dashboard-ticket-list__date col-md-2' - } - ]; - } - - getTableRows() { - return this.props.tickets.map(this.gerTicketTableObject.bind(this)); - } - - gerTicketTableObject(ticket) { - let titleText = (ticket.unread) ? ticket.title + ' (1)' : ticket.title; - - return { - number: ( - - {'#' + ticket.ticketNumber} - - ), - title: ( - - ), - department: ticket.department.name, - date: ticket.date, - highlighted: ticket.unread - }; - } } diff --git a/client/src/app/main/dashboard/dashboard-list-tickets/dashboard-list-tickets-page.scss b/client/src/app/main/dashboard/dashboard-list-tickets/dashboard-list-tickets-page.scss deleted file mode 100644 index 3c9439e1..00000000 --- a/client/src/app/main/dashboard/dashboard-list-tickets/dashboard-list-tickets-page.scss +++ /dev/null @@ -1,26 +0,0 @@ -@import "../../../../scss/vars"; - -.dashboard-ticket-list { - - &__number { - text-align: left; - } - - &__title { - text-align: left; - } - - &__department { - text-align: right; - } - - &__date { - text-align: right; - } - - &__title-link:hover, - &__title-link:focus { - outline: none; - text-decoration: underline; - } -} \ No newline at end of file diff --git a/client/src/data/fixtures/user-fixtures.js b/client/src/data/fixtures/user-fixtures.js index dd72ae59..529789bc 100644 --- a/client/src/data/fixtures/user-fixtures.js +++ b/client/src/data/fixtures/user-fixtures.js @@ -148,6 +148,7 @@ module.exports = [ language: 'en', unread: true, closed: false, + priority: 'low', author: { id: 12, name: 'Haskell Curry', @@ -196,6 +197,47 @@ module.exports = [ language: 'en', unread: false, closed: false, + priority: 'medium', + author: { + name: 'Haskell Curry', + email: 'haskell@lambda.com' + }, + owner: { + name: 'Steve Jobs' + }, + comments: [ + { + content: 'Do you have apache installed? It generally happens if you dont have apache.', + author: { + name: 'Steve Jobs', + email: 'jobs@steve.com', + staff: true + } + }, + { + content: 'I have already installed apache, but the problem persists', + author: { + name: 'Haskell Curry', + steve: 'haskell@lambda.com', + staff: false + } + } + ] + }, + { + ticketNumber: '878552', + title: 'Lorem ipsum door', + content: 'I had a problem with the installation of the php server', + department: { + id: 2, + name: 'Environment Setup' + }, + date: '15 Apr 2016', + file: 'http://www.opensupports.com/some_file.zip', + language: 'en', + unread: false, + closed: false, + priority: 'high', author: { name: 'Haskell Curry', email: 'haskell@lambda.com' diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 8335a733..d76fc07d 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -55,6 +55,12 @@ export default { 'USER_SYSTEM': 'User System', 'EMAIL_TEMPLATES': 'Email Templates', 'FILTERS_CUSTOM_FIELDS': 'Filters and Custom Fields', + 'PRIORITY': 'Priority', + 'NUMBER': 'Number', + 'HIGH': 'High', + 'MEDIUM': 'Medium', + 'LOW': 'Low', + 'TITLE': 'Title', //ERRORS 'EMAIL_OR_PASSWORD': 'Email or password invalid',