Merge branch 'PR-45' into PR-54

remotes/origin/PR-58
booblegum 9 years ago
commit cb45ce94e2
  1. 5
      archilance/urls.py
  2. BIN
      assets/img/icons/icon_eye.png
  3. BIN
      assets/img/icons/icon_speach-ball_gray.png
  4. BIN
      assets/img/icons/icon_сertificate-512.png
  5. 68
      assets/js/build/create_worksell.js
  6. 203
      assets/js/build/customer_profile.js
  7. 4
      assets/js/build/home_page.js
  8. 61
      assets/js/build/init_create_worksell.js
  9. 61
      assets/js/build/init_customer_project_create.js
  10. 2
      assets/js/chat.js
  11. 12
      assets/js/src/customer_profile.js
  12. 24
      assets/js/src/seeds/bootstrap_tabs.js
  13. 6
      assets/js/src/seeds/show_hide.js
  14. 21
      assets/js/src/seeds/sort_by.js
  15. 2
      assets/sass/base/_colors.sass
  16. 99
      assets/sass/components/custom-components.sass
  17. 26
      assets/sass/main.sass
  18. 6
      assets/sass/modules/_mods.sass
  19. 5420
      assets/sass/old_main.sass
  20. 0
      chat/settings/__init__.py
  21. 20
      projects/migrations/0051_realty_state.py
  22. 21
      projects/migrations/0052_realty_created.py
  23. 18
      projects/models.py
  24. 1
      projects/static/css/project_filter.css
  25. 4
      projects/templates/project_detail.html
  26. 168
      projects/views.py
  27. 11
      specializations/models.py
  28. 4
      templates/home.html
  29. 162
      templates/partials/_base.html
  30. 2
      templates/partials/base.html
  31. 2
      templates/partials/header.html
  32. 13
      users/forms.py
  33. 11
      users/models.py
  34. 1
      users/static/css/user_profile_edit.css
  35. 178
      users/static/sass/customer-profile.sass
  36. 42
      users/templates/customer_profile.html
  37. 105
      users/templates/partials/inc-customer_profile-info.html
  38. 114
      users/templates/partials/inc-objects.html
  39. 99
      users/templates/partials/inc-projects.html
  40. 82
      users/templates/partials/tabs/tab-in_work_projects.html
  41. 48
      users/templates/partials/tabs/tab-objects.html
  42. 39
      users/templates/partials/tabs/tab-open_projects.html
  43. 29
      users/templates/partials/tabs/tab-rewiews.html
  44. 0
      users/templates/trash/customer_profile_current_projects.html
  45. 5
      users/templates/trash/customer_profile_info_block.html
  46. 0
      users/templates/trash/customer_profile_open_projects.html
  47. 0
      users/templates/trash/customer_profile_reviews.html
  48. 0
      users/templates/trash/customer_profile_trashed_projects.html
  49. 2
      users/templates/user_financial_info_edit.html
  50. 68
      users/templates/user_profile_edit.html
  51. 2
      users/templates/user_profile_edit_old.html
  52. 11
      users/urls.py
  53. 62
      users/views.py
  54. 2
      webpack.config.js

@ -10,6 +10,7 @@ from wagtail.wagtailcore import urls as wagtail_urls
from common.views import CustomRegistrationView
from wallets.views import TmpCheckOrderView, TmpPaymentAvisoView
from .views import HomeTemplateView, TestChatTemplateView, TestView
from projects.views import CustomerRealtyTrashView, CustomerRealtyDeleteView, CustomerRealtyRestoreView, SortRealtyBy
urlpatterns = [
url(r'^$', HomeTemplateView.as_view()),
@ -18,6 +19,10 @@ urlpatterns = [
url(r'^work_sell/', include('work_sell.urls')),
url(r'^test/$', TestView.as_view(), name='test'),
url(r'^projects/', include('projects.urls')),
url(r'^object/(?P<pk>\d+)/trash/$', CustomerRealtyTrashView.as_view(), name='customer-object-trash'),
url(r'^object/(?P<pk>\d+)/delete/$', CustomerRealtyDeleteView.as_view(), name='customer-object-delete'),
url(r'^object/(?P<pk>\d+)/restore/$', CustomerRealtyRestoreView.as_view(), name='customer-object-restore'),
url(r'^objects/sort/$', SortRealtyBy.as_view(), name='sort-realty-by'),
url(r'^reviews/', include('reviews.urls')),
url(r'^wallets/', include('wallets.urls')),
url(r'^chat/', include('chat.urls')),

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

@ -46,8 +46,6 @@
'use strict';
var _file_upload = __webpack_require__(1);
var _image_upload = __webpack_require__(11);
var _scroll_on_required = __webpack_require__(8);
@ -59,8 +57,6 @@
var _ajax_send_form_data = __webpack_require__(12);
$(function () {
// fileUploadInit();
// previewImg();
(0, _image_upload.imageUploadInit)();
(0, _scroll_on_required.scrollOnRequiredInit)();
(0, _popups.showPopupsInit)();
@ -71,54 +67,7 @@
});
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.fileUploadInit = undefined;
var _utils = __webpack_require__(2);
function fileUploadInit() {
var $fileUploadContainer = $('#fileUploadContainer');
$('#fileUploadAddBtn').on('click', function ($evt) {
$fileUploadContainer.find('.file-upload-widget').last().find('.file-upload-input').click();
});
$fileUploadContainer.on('change', '.file-upload-input', function ($evt) {
var $fileInput = $(this);
var $fileUploadWidget = $fileInput.closest('.file-upload-widget');
var filePath = $fileInput.val().replace(/\\/g, '/');
var fileName = path.basename(filePath);
//var fileExt = path.extname(filePath)
var fileSize = $fileInput.get(0).files && (0, _utils.humanFileSize)($fileInput.get(0).files[0].size);
if (fileName) {
$fileUploadWidget.find('.file-upload-label').text(fileName + ' ' + fileSize);
var $newFileUploadWidget = $fileUploadWidget.clone();
$newFileUploadWidget.find('.file-upload-label').text('');
$fileUploadContainer.find('ul').first().append($newFileUploadWidget);
$fileUploadWidget.css('display', 'block');
}
});
$fileUploadContainer.on('click', '.file-upload-remove-btn', function ($evt) {
var $btn = $(this);
$btn.closest('.file-upload-widget').remove();
});
}
exports.fileUploadInit = fileUploadInit;
/***/ },
/* 1 */,
/* 2 */
/***/ function(module, exports) {
@ -431,11 +380,8 @@
function sendFormData(e) {
e.preventDefault();
// console.log("send dat later");
var $target = $(e.target);
var $form = $target.closest("form");
// console.log("actions = ", $form.attr("action"));
// let url = $form.attr("action");
// let formData = $form.serializeArray();
var formData = new FormData($form[0]);
$.ajax({
@ -447,10 +393,8 @@
xhr.setRequestHeader("X-CSRFToken", (0, _utils.getCookie)('csrftoken'));
},
success: function success(data) {
// console.log("success xhr -->", xhr);
// let data = xhr.responseJSON;
// console.log('success data -->', data);
// console.log('success data -->', data.redirect_to);
window.location.href = data.redirect_to;
},
cache: false,
@ -459,25 +403,15 @@
error: function error(xhr, ajaxOptions, thrownError) {
var status = xhr.status;
$('.error').removeClass('error');
// console.log('error data -->', xhr.responseJSON);
if (status == 400) {
// let data = JSON.parse(xhr.responseText);
var data = xhr.responseJSON;
$.each(data, function (key, value) {
// let ul = $("<ul class='errorlist'></ul>");
// for (let error of value) {
// ul.append(`<li>${error}</li>`)
// }
// console.log("key = ", key, "value =", value);
var $header = $form.find("[name=" + key + "]").siblings('.required');
// console.log("$header = ", $header);
if ($header.length > 0) {
$header.addClass("error");
}
});
window.scrollOnRequiredInit();
// console.log('captcha error = ', data.captcha);
// console.log('data type = ', typeof data);
} else {
console.log('xhr = ', xhr);
}

@ -0,0 +1,203 @@
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
var _show_hide = __webpack_require__(13);
var _bootstrap_tabs = __webpack_require__(14);
var _sort_by = __webpack_require__(15);
$(function () {
(0, _bootstrap_tabs.restoreTab)();
(0, _bootstrap_tabs.tabsHashInit)();
window.toggler = _show_hide.toggler;
window.sortRealtyBy = _sort_by.sortRealtyBy;
// on load of the page: switch to the currently selected tab
});
/***/ },
/* 1 */,
/* 2 */
/***/ function(module, exports) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
if (cookie.substring(0, name.length + 1) == name + '=') {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function humanFileSize(bytes, si) {
var thresh = si ? 1000 : 1024;
if (Math.abs(bytes) < thresh) return bytes + ' B';
var units = si ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
var u = -1;
do {
bytes /= thresh;
++u;
} while (Math.abs(bytes) >= thresh && u < units.length - 1);
return bytes.toFixed(1) + ' ' + units[u];
}
exports.humanFileSize = humanFileSize;
exports.getCookie = getCookie;
/***/ },
/* 3 */,
/* 4 */,
/* 5 */,
/* 6 */,
/* 7 */,
/* 8 */,
/* 9 */,
/* 10 */,
/* 11 */,
/* 12 */,
/* 13 */
/***/ function(module, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function toggler(from, divId) {
$(from).toggleClass("clicked");
$("#" + divId).toggle();
}
exports.toggler = toggler;
/***/ },
/* 14 */
/***/ function(module, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function tabsHashInit() {
// store the currently selected tab in the hash value
$("a[data-toggle=tab]").on("shown.bs.tab", function (e) {
var target = $(e.target);
if (target.hasClass("tab-inserted")) {
target.siblings(".active").removeClass("active");
target.addClass("active");
return;
}
var id = target.attr("href").substr(1);
var scrollmem = $('body').scrollTop() || $('html').scrollTop();
window.location.hash = id;
$('html,body').scrollTop(scrollmem);
});
}
function restoreTab() {
// on load of the page: switch to the currently selected tab
var hash = window.location.hash;
var a = $("a[data-toggle=\"tab\"][href=\"" + hash + "\"]");
hash && a.tab('show');
}
exports.tabsHashInit = tabsHashInit;
exports.restoreTab = restoreTab;
/***/ },
/* 15 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.sortRealtyBy = undefined;
var _utils = __webpack_require__(2);
function sortRealtyBy(data, container_id) {
console.log("sort_by = ", data);
console.log("container_id = ", container_id);
var url = '/objects/sort/';
$.ajax({
url: url,
type: 'POST',
data: data,
beforeSend: function beforeSend(xhr) {
xhr.setRequestHeader("X-CSRFToken", (0, _utils.getCookie)('csrftoken'));
},
success: function success(data) {
$(container_id).html(data);
// console.log("data = ", data);
}
});
}
exports.sortRealtyBy = sortRealtyBy;
/***/ }
/******/ ]);

@ -47,7 +47,7 @@
'use strict';
var _popupYoutube = __webpack_require__(13);
var _popupYoutube = __webpack_require__(16);
$(function () {
(0, _popupYoutube.popupYoutubeInit)();
@ -55,7 +55,7 @@
/***/ },
/***/ 13:
/***/ 16:
/***/ function(module, exports) {
'use strict';

@ -46,27 +46,27 @@
'use strict';
var _SelectedContainer = __webpack_require__(14);
var _SelectedContainer = __webpack_require__(17);
var _SelectedContainer2 = _interopRequireDefault(_SelectedContainer);
var _SelectedContainerCreate = __webpack_require__(18);
var _SelectedContainerCreate = __webpack_require__(21);
var _SelectedContainerCreate2 = _interopRequireDefault(_SelectedContainerCreate);
var _NoTreeSelect = __webpack_require__(19);
var _NoTreeSelect = __webpack_require__(22);
var _NoTreeSelect2 = _interopRequireDefault(_NoTreeSelect);
var _TreeSelect = __webpack_require__(21);
var _TreeSelect = __webpack_require__(24);
var _TreeSelect2 = _interopRequireDefault(_TreeSelect);
var _SingleTreeSelect = __webpack_require__(22);
var _SingleTreeSelect = __webpack_require__(25);
var _SingleTreeSelect2 = _interopRequireDefault(_SingleTreeSelect);
var _SelectOrCreate = __webpack_require__(23);
var _SelectOrCreate = __webpack_require__(26);
var _SelectOrCreate2 = _interopRequireDefault(_SelectOrCreate);
@ -180,7 +180,10 @@
/* 11 */,
/* 12 */,
/* 13 */,
/* 14 */
/* 14 */,
/* 15 */,
/* 16 */,
/* 17 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
@ -195,15 +198,15 @@
var _desc, _value, _class; // `
var _DataTree = __webpack_require__(15);
var _DataTree = __webpack_require__(18);
var _DataTree2 = _interopRequireDefault(_DataTree);
var _NoTreeData = __webpack_require__(16);
var _NoTreeData = __webpack_require__(19);
var _NoTreeData2 = _interopRequireDefault(_NoTreeData);
var _decorators = __webpack_require__(17);
var _decorators = __webpack_require__(20);
var _decorators2 = _interopRequireDefault(_decorators);
@ -434,7 +437,7 @@
exports.default = SelectedContainer;
/***/ },
/* 15 */
/* 18 */
/***/ function(module, exports) {
"use strict";
@ -589,7 +592,7 @@
exports.default = DataTree;
/***/ },
/* 16 */
/* 19 */
/***/ function(module, exports) {
"use strict";
@ -645,7 +648,7 @@
exports.default = NoTreeData;
/***/ },
/* 17 */
/* 20 */
/***/ function(module, exports) {
"use strict";
@ -729,7 +732,7 @@
// export {onBind};
/***/ },
/* 18 */
/* 21 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
@ -745,11 +748,11 @@
var _desc, _value, _class;
var _SelectedContainer2 = __webpack_require__(14);
var _SelectedContainer2 = __webpack_require__(17);
var _SelectedContainer3 = _interopRequireDefault(_SelectedContainer2);
var _decorators = __webpack_require__(17);
var _decorators = __webpack_require__(20);
var _decorators2 = _interopRequireDefault(_decorators);
@ -830,7 +833,7 @@
exports.default = SelectedContainerCreate;
/***/ },
/* 19 */
/* 22 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
@ -844,9 +847,9 @@
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
var _AbsBaseSelect2 = __webpack_require__(20);
var _AbsBaseSelect2 = __webpack_require__(23);
var _NoTreeData = __webpack_require__(16);
var _NoTreeData = __webpack_require__(19);
var _NoTreeData2 = _interopRequireDefault(_NoTreeData);
@ -913,7 +916,7 @@
exports.default = NoTreeSelect;
/***/ },
/* 20 */
/* 23 */
/***/ function(module, exports) {
"use strict";
@ -1457,7 +1460,7 @@
exports.AbsBaseSelect = AbsBaseSelect;
/***/ },
/* 21 */
/* 24 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
@ -1471,9 +1474,9 @@
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
var _AbsBaseSelect2 = __webpack_require__(20);
var _AbsBaseSelect2 = __webpack_require__(23);
var _DataTree = __webpack_require__(15);
var _DataTree = __webpack_require__(18);
var _DataTree2 = _interopRequireDefault(_DataTree);
@ -1582,7 +1585,7 @@
exports.default = TreeSelect;
/***/ },
/* 22 */
/* 25 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
@ -1594,9 +1597,9 @@
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _AbsBaseSelect = __webpack_require__(20);
var _AbsBaseSelect = __webpack_require__(23);
var _TreeSelect2 = __webpack_require__(21);
var _TreeSelect2 = __webpack_require__(24);
var _TreeSelect3 = _interopRequireDefault(_TreeSelect2);
@ -1677,7 +1680,7 @@
exports.default = SingleTreeSelect;
/***/ },
/* 23 */
/* 26 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
@ -1691,9 +1694,9 @@
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
var _AbsBaseSelect2 = __webpack_require__(20);
var _AbsBaseSelect2 = __webpack_require__(23);
var _NoTreeData = __webpack_require__(16);
var _NoTreeData = __webpack_require__(19);
var _NoTreeData2 = _interopRequireDefault(_NoTreeData);

@ -46,27 +46,27 @@
'use strict';
var _SelectedContainer = __webpack_require__(14);
var _SelectedContainer = __webpack_require__(17);
var _SelectedContainer2 = _interopRequireDefault(_SelectedContainer);
var _SelectedContainerCreate = __webpack_require__(18);
var _SelectedContainerCreate = __webpack_require__(21);
var _SelectedContainerCreate2 = _interopRequireDefault(_SelectedContainerCreate);
var _NoTreeSelect = __webpack_require__(19);
var _NoTreeSelect = __webpack_require__(22);
var _NoTreeSelect2 = _interopRequireDefault(_NoTreeSelect);
var _TreeSelect = __webpack_require__(21);
var _TreeSelect = __webpack_require__(24);
var _TreeSelect2 = _interopRequireDefault(_TreeSelect);
var _SingleTreeSelect = __webpack_require__(22);
var _SingleTreeSelect = __webpack_require__(25);
var _SingleTreeSelect2 = _interopRequireDefault(_SingleTreeSelect);
var _SelectOrCreate = __webpack_require__(23);
var _SelectOrCreate = __webpack_require__(26);
var _SelectOrCreate2 = _interopRequireDefault(_SelectOrCreate);
@ -215,7 +215,10 @@
/* 11 */,
/* 12 */,
/* 13 */,
/* 14 */
/* 14 */,
/* 15 */,
/* 16 */,
/* 17 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
@ -230,15 +233,15 @@
var _desc, _value, _class; // `
var _DataTree = __webpack_require__(15);
var _DataTree = __webpack_require__(18);
var _DataTree2 = _interopRequireDefault(_DataTree);
var _NoTreeData = __webpack_require__(16);
var _NoTreeData = __webpack_require__(19);
var _NoTreeData2 = _interopRequireDefault(_NoTreeData);
var _decorators = __webpack_require__(17);
var _decorators = __webpack_require__(20);
var _decorators2 = _interopRequireDefault(_decorators);
@ -469,7 +472,7 @@
exports.default = SelectedContainer;
/***/ },
/* 15 */
/* 18 */
/***/ function(module, exports) {
"use strict";
@ -624,7 +627,7 @@
exports.default = DataTree;
/***/ },
/* 16 */
/* 19 */
/***/ function(module, exports) {
"use strict";
@ -680,7 +683,7 @@
exports.default = NoTreeData;
/***/ },
/* 17 */
/* 20 */
/***/ function(module, exports) {
"use strict";
@ -764,7 +767,7 @@
// export {onBind};
/***/ },
/* 18 */
/* 21 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
@ -780,11 +783,11 @@
var _desc, _value, _class;
var _SelectedContainer2 = __webpack_require__(14);
var _SelectedContainer2 = __webpack_require__(17);
var _SelectedContainer3 = _interopRequireDefault(_SelectedContainer2);
var _decorators = __webpack_require__(17);
var _decorators = __webpack_require__(20);
var _decorators2 = _interopRequireDefault(_decorators);
@ -865,7 +868,7 @@
exports.default = SelectedContainerCreate;
/***/ },
/* 19 */
/* 22 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
@ -879,9 +882,9 @@
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
var _AbsBaseSelect2 = __webpack_require__(20);
var _AbsBaseSelect2 = __webpack_require__(23);
var _NoTreeData = __webpack_require__(16);
var _NoTreeData = __webpack_require__(19);
var _NoTreeData2 = _interopRequireDefault(_NoTreeData);
@ -948,7 +951,7 @@
exports.default = NoTreeSelect;
/***/ },
/* 20 */
/* 23 */
/***/ function(module, exports) {
"use strict";
@ -1492,7 +1495,7 @@
exports.AbsBaseSelect = AbsBaseSelect;
/***/ },
/* 21 */
/* 24 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
@ -1506,9 +1509,9 @@
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
var _AbsBaseSelect2 = __webpack_require__(20);
var _AbsBaseSelect2 = __webpack_require__(23);
var _DataTree = __webpack_require__(15);
var _DataTree = __webpack_require__(18);
var _DataTree2 = _interopRequireDefault(_DataTree);
@ -1617,7 +1620,7 @@
exports.default = TreeSelect;
/***/ },
/* 22 */
/* 25 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
@ -1629,9 +1632,9 @@
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _AbsBaseSelect = __webpack_require__(20);
var _AbsBaseSelect = __webpack_require__(23);
var _TreeSelect2 = __webpack_require__(21);
var _TreeSelect2 = __webpack_require__(24);
var _TreeSelect3 = _interopRequireDefault(_TreeSelect2);
@ -1712,7 +1715,7 @@
exports.default = SingleTreeSelect;
/***/ },
/* 23 */
/* 26 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
@ -1726,9 +1729,9 @@
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
var _AbsBaseSelect2 = __webpack_require__(20);
var _AbsBaseSelect2 = __webpack_require__(23);
var _NoTreeData = __webpack_require__(16);
var _NoTreeData = __webpack_require__(19);
var _NoTreeData2 = _interopRequireDefault(_NoTreeData);

@ -29,7 +29,7 @@ window.confirm = function (message, callback, caption) {
var SocketHandler = function () {
//TODO: получать порт с файла настроек
domain = domain.replace(':' + port, '');
domain = domain.replace(':' + port, ':8888');
if (window.location.protocol == 'https:') {
var ws = "wss://";
} else {

@ -0,0 +1,12 @@
import {toggler} from './seeds/show_hide'
import {tabsHashInit, restoreTab} from './seeds/bootstrap_tabs'
import {sortRealtyBy} from './seeds/sort_by'
$(function () {
restoreTab();
tabsHashInit();
window.toggler = toggler;
window.sortRealtyBy = sortRealtyBy;
// on load of the page: switch to the currently selected tab
});

@ -0,0 +1,24 @@
function tabsHashInit() {
// store the currently selected tab in the hash value
$("a[data-toggle=tab]").on("shown.bs.tab", function (e) {
let target = $(e.target);
if(target.hasClass("tab-inserted")){
target.siblings(".active").removeClass("active");
target.addClass("active");
return
}
let id = target.attr("href").substr(1);
let scrollmem = $('body').scrollTop() || $('html').scrollTop();
window.location.hash = id;
$('html,body').scrollTop(scrollmem);
});
}
function restoreTab() {
// on load of the page: switch to the currently selected tab
let hash = window.location.hash;
let a = $(`a[data-toggle="tab"][href="${hash}"]`);
hash && a.tab('show');
}
export {tabsHashInit, restoreTab}

@ -0,0 +1,6 @@
function toggler(from, divId) {
$(from).toggleClass("clicked");
$("#" + divId).toggle();
}
export {toggler}

@ -0,0 +1,21 @@
import {getCookie} from '../utils'
function sortRealtyBy(data, container_id) {
console.log("sort_by = ", data);
console.log("container_id = ", container_id);
let url = '/objects/sort/';
$.ajax({
url: url,
type: 'POST',
data: data,
beforeSend: function (xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'))
},
success: function (data) {
$(container_id).html(data);
// console.log("data = ", data);
}
})
}
export {sortRealtyBy}

@ -1,6 +1,6 @@
$col_component_headers: #000
//$colors: (c_red: #ff0000, c_green: #00FF00, c_blue: #0000FF)
$component_colors: (header: #000, header_favicon: #5e5e5e, border: #cccccc, select: #FF0029)
$component_colors: (header: #000, header_favicon: #5e5e5e, border: #cccccc, select: #FF0029, footer_background: #F7F7F7)
// #{map_get($component_colors, border)}

@ -10,6 +10,9 @@
label
font-weight: normal
li.active
border-top: 2px solid black
.simple-input
height: 51px
width: 100%
@ -65,6 +68,7 @@ textarea.description
font-style: italic
.btn-simple
text-transform: uppercase
border-radius: 40px
padding: 10px 15px
border: 1px solid #FF0029
@ -74,9 +78,9 @@ textarea.description
font-style: normal
font-size: 14pt
display: inline-block
color: #000
color: #4e4c4c
&:hover
color: #000
color: #4e4c4c
text-decoration: none
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2)
-webkit-transform: scale(1.04)
@ -87,6 +91,38 @@ textarea.description
&:active
outline: 0 !important
&.-small
padding: 5px 14px
font-size: 10pt
&.-gray
border: 1px solid #bdbdbd
&.-up_down:after
content: "\e252"
font-family: 'Glyphicons Halflings'
position: relative
right: -5px
top: 3px
font-style: normal
font-weight: normal
font-size: 10pt
line-height: 1
padding-right: 20px
-webkit-font-smoothing: antialiased
.icon-edit
//padding-left: 30px
//content: ''
display: inline-block
width: 40px
height: 20px
background:
image: url("#{$static}/img/menuUser.png")
//color: #00A66E
repeat: no-repeat
position: 0 0
.upload-new, .btn-simple
transition: all 0.3s
cursor: pointer
@ -259,3 +295,62 @@ textarea.description
&.less
&:before
content: 'свернуть'
.btn-group
.btn
padding: 15px 30px
.btn-round
$radius: 30px
.btn:first-child
border-top-left-radius: $radius
border-bottom-left-radius: $radius
.btn:last-child
border-top-right-radius: $radius
border-bottom-right-radius: $radius
.link-sort button
font-size: 14px
font-family: 'Arial-MT-Regular', sans-serif
color: #6b6b6b
padding: 11px 23px
border-radius: 40px
margin-right: 6px
border: 1px solid #c2c2c2
background-color: #fff
&:after
content: "\e252"
font-family: 'Glyphicons Halflings'
position: relative
right: -5px
top: 3px
font-style: normal
font-weight: normal
line-height: 1
-webkit-font-smoothing: antialiased
.btn-up_down
width: 110px
text-transform: uppercase
font-size: 10pt
font-family: 'Myriad', sans-serif
color: #6b6b6b
padding: 11px 23px
border-radius: 40px
margin-right: 6px
border: 1px solid #c2c2c2
background-color: #fff
&:after
content: "\e253"
font-family: 'Glyphicons Halflings'
font-style: normal
font-weight: normal
line-height: 1
-webkit-font-smoothing: antialiased
&.-small
padding: 5px 10px
.btn-up_down.clicked
&:after
content: "\e252"

@ -1,3 +1,9 @@
/********************************
* Общие стили для ВСЕХ страниц *
* 10 раз подумайет, прежде чем *
* добавить сюда стили *
********************************/
@import "base/fonts"
@import "base/colors"
@import "base/variavles"
@ -8,6 +14,12 @@ body
font-size: 11pt
font-family: Arial-MT-Regular, Arial, sans-serif
.btn-default:focus
outline: 0
.hidden
display: none
.main-scope
> .row
border-right: 1px solid #{map_get($component_colors, border)}
@ -21,7 +33,6 @@ body
padding: 0 100px
text-align: center
border-bottom: 1px solid #{map_get($component_colors, border)}
//width: 100%
h1
font:
family: 'pfbeausanspro-thin', sans-serif
@ -41,12 +52,6 @@ body
@extend %header
max-width: 100%
.logical-block
$pad: 30px
padding-top: $pad
padding-bottom: $pad
margin-top: $pad
.select-text
color: #{map_get($component_colors, select)}
@ -56,3 +61,10 @@ body
.slide.active
display: block
.footer-wrapper
background-color: #{map_get($component_colors, footer_background)}
.footer-border
border-left: 1px solid #{map_get($component_colors, border)}
border-right: 1px solid #{map_get($component_colors, border)}

@ -8,11 +8,15 @@
align-items: flex-end
.mod-align-center
display: flex
display: flex !important
-ms-flex-align: center
-webkit-align-items: center
-webkit-box-align: center
align-items: center
&-inline
display: inline-flex !important
align-items: center
.mod-no-padding
padding: 0 !important

File diff suppressed because it is too large Load Diff

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-12-21 09:57
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('projects', '0050_auto_20161207_1637'),
]
operations = [
migrations.AddField(
model_name='realty',
name='state',
field=models.CharField(choices=[('active', 'Активный'), ('trashed', 'В корзине'), ('deleted', 'Удален')], default='active', max_length=20),
),
]

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-12-22 07:25
from __future__ import unicode_literals
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('projects', '0051_realty_state'),
]
operations = [
migrations.AddField(
model_name='realty',
name='created',
field=models.DateTimeField(default=django.utils.timezone.now),
),
]

@ -7,6 +7,7 @@ from django.utils import timezone
from hitcount.models import HitCountMixin
from mptt.managers import TreeManager
from mptt.models import TreeForeignKey, MPTTModel
from django.db.models import Sum, Count
_.map = _.map_;
_.filter = _.filter_
@ -68,15 +69,25 @@ class ConstructionType(models.Model):
class Realty(models.Model):
STATES = (
('active', 'Активный'),
('trashed', 'В корзине'),
('deleted', 'Удален'),
)
building_classification = TreeForeignKey(BuildingClassfication, related_name='realties', null=True, blank=True)
construction_type = models.ForeignKey(ConstructionType, related_name='realties', null=True, blank=True)
location = TreeForeignKey('common.Location', related_name='realties', null=True, blank=True)
name = models.CharField(max_length=255, blank=True)
created = models.DateTimeField(default=timezone.now)
# Виртуальные объекты привязываются к Проектам, для которых Объект не создан явно
is_virtual = models.BooleanField(default=False, editable=False)
location = TreeForeignKey('common.Location', related_name='realties', null=True, blank=True)
name = models.CharField(max_length=255, blank=True)
state = models.CharField(default='active', max_length=20, choices=STATES)
user = models.ForeignKey(User, related_name='realties') # Do we actually need this field?
def __str__(self):
if self.is_virtual:
return "Virtual"
return self.name
class Meta:
@ -139,6 +150,9 @@ class Project(models.Model, HitCountMixin):
def get_team_answers(self):
return _.filter(self.answers.all(), lambda a: isinstance(a.author, Team))
def message_count(self):
return self.answers.aggregate(c=Count('messages'))['c']
class ProjectFile(models.Model):
file = models.FileField(upload_to='projects/project_files/')

@ -24,6 +24,7 @@ body {
.header {
display: block;
font-size: 12pt;
color: black;
}

@ -34,7 +34,7 @@
{% endif %}
<div class="col-lg-4">
<a href="{% url 'users:customer-profile-open-projects' project.customer.pk %}" class="aLinkExe">
<a href="{% url 'users:customer-profile' project.customer.pk %}" class="aLinkExe">
<div class="imgExecutor">
{% if project.customer.avatar %}
{% thumbnail project.customer.avatar "125x125" crop="center" as im %}
@ -46,7 +46,7 @@
</div>
</a>
<p class="nameExecutor">
<a href="{% url 'users:customer-profile-open-projects' project.customer.pk %}">{{ project.customer.get_full_name }}
<a href="{% url 'users:customer-profile' project.customer.pk %}">{{ project.customer.get_full_name }}
[{{ project.customer.username }}]</a>
</p>
<p class="navv2">На сайте {{ project.created|naturaltime }}</p>

@ -1,7 +1,7 @@
import json
from abc import ABC
from pprint import pformat
import natsort
import pydash as _
from django.conf import settings
from django.contrib import messages
@ -10,7 +10,7 @@ from django.core.exceptions import PermissionDenied
from django.core.files.base import ContentFile
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.core.urlresolvers import reverse, reverse_lazy
from django.db.models import Q
from django.db.models import Q, Count, Sum
from django.http import HttpResponseForbidden, JsonResponse, HttpResponseRedirect, HttpResponse, Http404
from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic import DetailView, CreateView, DeleteView, View, UpdateView, TemplateView
@ -53,8 +53,6 @@ from .forms import (
PortfolioForm,
ProjectAnswerForm,
ProjectAnswerMessageForm,
ProjectFilterForm,
ProjectFilterRealtyForm,
ProjectWorkTypeSuggestionForm,
RealtyForm,
RealtyFormNew
@ -405,86 +403,20 @@ class ProjectFilterView(BaseMixin, View):
return render(request, 'partials/inc-projects-results.html', self.get_context(request.POST))
# class CustomerProjectCreateView(BaseMixin, View):
# form_class = CustomerProjectEditForm
# realty_form = RealtyForm
# work_type_suggestion_form = ProjectWorkTypeSuggestionForm
# template_name = 'customer_project_create.html'
#
# def dispatch(self, request, *args, **kwargs):
# if request.user.is_authenticated() and request.user.is_customer():
# return super().dispatch(request, *args, **kwargs)
# else:
# raise PermissionDenied
#
# def get(self, request, *args, **kwargs):
# context = self.get_context_data(**_.merge({}, request.GET, kwargs))
#
# form = self.form_class(request=request)
# realty_form = self.realty_form(request=request, prefix='realty_form')
# work_type_suggestion_form = self.work_type_suggestion_form(request=request, prefix='work_type_suggestion')
#
# context.update({
# 'form': form,
# 'realty_form': realty_form,
# 'work_type_suggestion_form': work_type_suggestion_form,
# })
#
# return render(request, self.template_name, context)
#
# def post(self, request, *args, **kwargs):
# form = self.form_class(request.POST,
# request=request) # Passing `request.FILES` seems unnecessary here. Files are added manually below
#
# form.is_valid()
# realty = form.cleaned_data.get('realty')
#
# if realty:
# realty_form = self.realty_form(request.POST, instance=realty, request=request, prefix='realty_form')
# else:
# realty_form = self.realty_form(request.POST, request=request, prefix='realty_form')
#
# if form.is_valid() and realty_form.is_valid():
# project = form.save(commit=False)
# project.customer = request.user
# project.save()
# form.save_m2m()
#
# Order.objects.create(project=project, secure=project.deal_type == 'secure_deal')
#
# for file in request.FILES.getlist('new_files'):
# ProjectFile.objects.create(file=file, project=project)
#
# if realty:
# realty_form.save()
# else:
# realty = realty_form.save(commit=False)
# realty.user = request.user
# realty.save()
# realty_form.save_m2m()
#
# project.realty = realty # Connect a realty with a project
# project.save()
#
# messages.info(request, 'Проект успешно создан')
# redirect_to = reverse('projects:detail', kwargs={'pk': project.pk})
# return redirect(redirect_to)
# else:
# if form.errors:
# messages.info(request, (
# '<p>Произошла ошибка (form)</p>'
# '<pre>{form}</pre>'
# ).format(form=pformat(form.errors)))
#
# if realty_form and realty_form.errors:
# messages.info(request, (
# '<p>Произошла ошибка (realty_form)</p>'
# '<pre>{realty_form}</pre>'
# ).format(realty_form=pformat(realty_form.errors)))
#
# context = self.get_context_data(**kwargs)
# context.update({'form': form, 'realty_form': realty_form})
# return render(request, self.template_name, context)
class SortRealtyBy(View):
def get_context(self):
print("request.POST = ", self.request.POST)
user_id = self.request.POST.get('user_id')
sort_by = self.request.POST.get('sortBy')
state = self.request.POST.get('state')
objects = Realty.objects.filter(user__id=user_id, state=state, is_virtual=False)
if sort_by == 'num_orders':
objects = objects.annotate(num_orders=Count('projects'))
return {"objects": objects.order_by('{}'.format(sort_by))}
def post(self, *args, **kwargs):
return render(self.request, 'partials/inc-objects.html', self.get_context())
class CustomerProjectCreateView(BaseMixin, View):
@ -493,12 +425,6 @@ class CustomerProjectCreateView(BaseMixin, View):
work_type_suggestion_form = ProjectWorkTypeSuggestionForm
template_name = 'customer_project_create.html'
# def dispatch(self, request, *args, **kwargs):
# if request.user.is_authenticated() and request.user.is_customer():
# return super().dispatch(request, *args, **kwargs)
# else:
# raise PermissionDenied
def get_context_data(self, **kwargs):
ctx = super().get_context_data()
# ctx['hide_user_type'] = False
@ -745,6 +671,68 @@ class CustomerProjectTrashView(View):
return redirect(redirect_to)
class AbcCustomerRealityChangeState(ABC, View):
new_state = ''
message_part = ''
def __init__(self, **kwargs):
if self.new_state not in [el[0] for el in Realty.STATES]:
raise AttributeError('new_state must be in {}'.format([el[0] for el in Realty.STATES]))
super().__init__(**kwargs)
# TODO: dispatch вынести в ABC класс
# def dispatch(self, request, *args, **kwargs):
def post(self, request, *args, **kwargs):
realty = get_object_or_404(Realty, pk=kwargs.get("pk"))
realty.state = self.new_state
realty.save()
realty.projects.all().update(state=self.new_state)
messages.info(request, 'Объект и все, связанные с ним проекты, {}'.format(self.message_part))
redirect_to = request.POST.get('next')
return redirect(redirect_to)
class CustomerRealtyTrashView(AbcCustomerRealityChangeState):
new_state = 'trashed'
message_part = 'перемещёны в корзину'
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated() and request.user.is_customer():
num_project_in_process = Project.objects.filter(realty__id=kwargs.get('pk')).filter(order__status="process").count()
if num_project_in_process:
raise PermissionDenied('Один или более Заказ, данного Объекта, уже находятся в работе. '
'Вы не можете переместить его в корзину.')
else:
return super().dispatch(request, *args, **kwargs)
raise PermissionDenied
class CustomerRealtyDeleteView(AbcCustomerRealityChangeState):
new_state = 'deleted'
message_part = 'удалены'
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated() and request.user.is_customer():
return super().dispatch(request, *args, **kwargs)
else:
raise PermissionDenied
class CustomerRealtyRestoreView(AbcCustomerRealityChangeState):
new_state = 'active'
message_part = 'восстановлены'
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated() and request.user.is_customer():
return super().dispatch(request, *args, **kwargs)
else:
raise PermissionDenied
class CustomerProjectRestoreView(View):
form_class = CustomerProjectRestoreForm

@ -14,6 +14,17 @@ class Specialization(MPTTModel):
def __str__(self):
return self.name
def full_path(self):
part = self
path = part.name
while True:
if part.parent.name != '_root':
# print(part.name)
part = part.parent
path = '{} / {}'.format(part.name, path)
else:
return path
class Meta:
get_latest_by = 'order'
ordering = ['order']

@ -24,7 +24,7 @@
<div class="infoBlock customer">
{% if request.user.is_authenticated and request.user.is_customer %}
<a class="to-profile"
href="{% url 'users:customer-profile-open-projects' pk=request.user.pk %}">Я заказчик</a>
href="{% url 'users:customer-profile' pk=request.user.pk %}">Я заказчик</a>
{% else %}
<a class="to-profile" href="{% url 'registration_register' %}?type=customer">Я заказчик</a>
{% endif %}
@ -133,7 +133,7 @@
</div>
</div>
</div>
<div style="background-color: #F7F7F7;">
<div class="footer-wrapper">
<div class="container">
{% include 'partials/footer.html' %}
</div>

@ -0,0 +1,162 @@
<!DOCTYPE html>
{% load staticfiles %}
{% load sass_tags %}
{#{% load compress %}#}
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta http-equiv='X-UA-Compatible' content='IE=edge, chrome=1'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<!--<meta name='viewport' content='initial-scale=1.0, user-scalable=no, maximum-scale=1'>-->
{% block head %}{% endblock %}
<title>PROEKTON</title>
{% block common_css %}
<link rel='stylesheet' href='{% static "css/bootstrap.css" %}'>
<link rel='stylesheet' href='{% static "css/font-awesome.min.css" %}'>
<link rel="stylesheet" href='{% static "lib/jquery-jgrowl/jquery.jgrowl.min.css" %}'>
<link rel='stylesheet' href='{% static "lib/jquery-ui/jquery-ui.css" %}'>
<link rel='stylesheet' href='{% sass_src "sass/main.sass" %}'>
{% if TEMPLATE_DEBUG %}
<link rel='stylesheet' href='{% static "css/dev-colors.css" %}'> <!-- Dev-time only, temporary!!! -->
{% endif %}
{% endblock %}
{% block personal_css %}
{% endblock %}
<link rel="icon" href="{% static 'img/favicon.jpg' %}" type="image/x-icon">
<link rel="shortcut icon" href="{% static 'img/favicon50.jpg' %}" type="image/x-icon">
<link rel="apple-touch-icon" href="{% static 'img/favicon128.jpg' %}" sizes="128x128">
<link rel="icon" type="image/png" href="{% static 'img/favicon50.jpg' %}" sizes="32x32">
<link rel="icon" type="image/png" href="{% static 'img/favicon18.jpg' %}" sizes="16x16">
{# {% endcompress %}#}
<meta name="keywords" content="">
<meta name="description" content="_TEXT_">
<meta name="yandex-verification" content="58d23691715ef942">
<link rel="canonical" href="_URL_">
</head>
<body>
{% if TEMPLATE_DEBUG %}
{% if messages %}
{% for message in messages %}
<div class="c"
style="position: relative; padding: 10px; margin-bottom: 6px; z-index: 100">{{ message|safe }}</div>
{% endfor %}
{% endif %}
{% endif %}
{% block header %}
{% include 'partials/header.html' %}
{% endblock %}
{% block content %}
<div style="min-height: 400px">
BASE TEMPLATE
</div>
{% endblock %}
{% block footer %}
<div class="container footer-border">
{% include 'partials/footer.html' %}
</div>
{% endblock %}
{% block common_js %}
<script src='{% static "js/jquery-2.2.3.min.js" %}'></script>
<script src='{% static "lib/jquery.cookie/jquery.cookie.min.js" %}'></script>
<script src='{% static "js/bootstrap.min.js" %}'></script>
{% endblock %}
{% block personal_js %}
{% endblock %}
{#{% compress js %}#}
{# <script src='{% static "js/jquery-2.2.3.min.js" %}'></script>#}
{# <script src='{% static "lib/jquery-ui/jquery-ui.js" %}'></script>#}
{# <script src='{% static "lib/jquery-ui/i18n/datepicker-ru.js" %}'></script> <!-- jQueryUI Datepicker i18n -->#}
{# <script src='{% static "js/bootstrap.min.js" %}'></script>#}
{# <script src='{% static "lib/bootstrap-select/js/bootstrap-select.js" %}'></script>#}
{# <script src='{% static "lib/select2/select2.js" %}'></script>#}
{# <script src='{% static "lib/urijs/URI.min.js" %}'></script>#}
{# <script src='{% static "js/jquery.magnific-popup.min.js" %}'></script>#}
{# <script src='{% static "my-libs.js" %}'></script>#}
{% block websocket_js %}
<script src='{% static "lib/jquery-jgrowl/jquery.jgrowl.min.js" %}'></script>
<script>
function getOpenOrdersList() {
$.ajax({
url: '/api/orders?status=created',
type: 'get',
success: function (data) {
$.each(data.results, function (key, value) {
open_order_list.push(parseInt(value.id))
})
}
})
}
function message_count_plus(selector) {
var all_messages = $(selector);
var count = parseInt(all_messages.html()) + 1;
if (count > 99) count = '99+';
all_messages.html(count);
}
var SocketHandlerMain = function (userId) {
var domain = '{{ request.META.HTTP_HOST }}';
var port = '{{ request.META.SERVER_PORT }}';
var queryString = '{{ request.get_full_path }}';
if ((queryString.indexOf('/chat') != 0) && (queryString.indexOf('/users/contractor-office/work-projects') != 0)) {
domain = domain.replace(':' + port, ':8888');
if (window.location.protocol == 'https:') {
var ws = "wss://";
} else {
var ws = "ws://";
}
var url = ws + domain + '/chat/' + userId + '/';
var sock = new WebSocket(url);
var intervalId;
sock.onopen = function () {
intervalId = setInterval(function () {
sock.send('{"dummy": 1}');
}, 15000);
};
sock.onmessage = function (event) {
var notificationData = JSON.parse(event.data);
if (open_order_list.indexOf(parseInt(notificationData.order_id)) != -1) {
{# console.log("in");#}
message_count_plus('#my_office');
}
message_count_plus('.js-all-messages');
var outMessage = "";
if (notificationData.answer_type == 'add_message_contact') {
outMessage += "<a href='/chat/?user_id=" + notificationData.sender_id + "'>" + notificationData.msg + "<a>";
} else if ((notificationData.answer_type == 'approve_stages') || (notificationData.answer_type == 'add_message_order')) {
outMessage += "<a href='/chat/#order" + notificationData.order_id + "'>" + notificationData.msg + "<a>";
}
console.log("Вам пришло новое сообщение!<br />" + outMessage);
$.jGrowl("Вам пришло новое сообщение!<br />" + outMessage, {life: 15000});
};
this.add_message = function (messageData) {
sock.send(JSON.stringify(messageData));
};
}
};
var userId = '{{ request.user.pk }}';
if (userId) {
var socketMain = new SocketHandlerMain(userId);
var open_order_list = [];
getOpenOrdersList();
}
</script>
{% endblock %}
{#{% endcompress %}#}
</body>
</html>

@ -136,7 +136,7 @@
var queryString = '{{ request.get_full_path }}';
if ((queryString.indexOf('/chat') != 0) && (queryString.indexOf('/users/contractor-office/work-projects') != 0)) {
domain = domain.replace(':' + port, '');
domain = domain.replace(':' + port, ':8888');
if (window.location.protocol == 'https:') {
var ws = "wss://";
} else {

@ -8,7 +8,7 @@
{% if request.user.is_contractor %}
{% url 'users:contractor-profile' pk=request.user.pk as profile_url %}
{% elif request.user.is_customer %}
{% url 'users:customer-profile-open-projects' pk=request.user.pk as profile_url %}
{% url 'users:customer-profile' pk=request.user.pk as profile_url %}
{% endif %}
<link rel='stylesheet' href='{% sass_src "partials/sass/header.sass" %}'>

@ -322,6 +322,19 @@ class ContractorFilterForm(forms.Form):
super().__init__(*args, **kwargs)
class CustomerProfileForm(forms.ModelForm):
class Meta:
model = User
fields = (
'username',
'first_name',
'created',
'avatar',
'rating'
)
class CustomerProfileProjectRealtyForm(forms.Form):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')

@ -167,6 +167,17 @@ class User(AbstractBaseUser, PermissionsMixin):
elif self.location.level == 1:
return self.location.name
def country(self):
try:
return self.location.parent.parent.name
except AttributeError:
return 'None'
def city(self):
try:
return self.location.name
except AttributeError:
return 'None'
# @property
# def is_staff(self):
# return self.is_superuser

@ -9,6 +9,7 @@
}
.avatar {
background-color: #F1F1F1;
width: 228px;
height: 228px;
padding: 10px;

@ -0,0 +1,178 @@
@import "base/variavles"
@import "modules/mods"
//.avatarInset
// //width: 100%
// height: 224px
// img
// width: 100%
// height: 100%
// //padding: 10%
// background-color: #e4e4e4
.count
display: inline-block
width: 32px
height: 32px
border-radius: 100%
text-align: center
line-height: 32px
font-family: 'Arial-MT-Regular', sans-serif
overflow: hidden
color: black
background-color: #ccc
margin-left: 10px
.projects_count
display: inline-block
color: red
margin: 0 15px
.object
.object-header
font-size: 24px
color: #545151
font-weight: bold
a
color: #575454
a:hover
text-decoration: none
color: #000
.user_name
color: #131212
font-size: 16pt
line-height: 100%
.border.add_line:before
content: ''
position: relative
display: block
width: 100px
height: 3px
background-color: black
left: 62px
top: 0
//z-index: 1
//-webkit-transition: all 0.3s ease-out
//-moz-transition: all 0.3s ease-out
//transition: all 0.3s ease-out
.nav-tabs a
color: #0b0b0b
table.ratings
font-size: 14pt
td
padding: 10px
.positive
color: #0b0b0b
.neutral
color: grey
.negative
color: red
table.projects
width: 100%
td
padding: 5px
tr:nth-child(2n)
background-color: #E8E8E8
.cut
display: inline-block
text-overflow: ellipsis
max-width: 550px
overflow: hidden
word-wrap: break-word
white-space: nowrap
%icons
margin-left: 24px
display: flex
align-items: center
&:before
content: ''
display: inline-block
width: 20px
height: 20px
background-size: cover
position: relative
left: -5px
.icon-rating
@extend %icons
&:before
background: url('#{$static}/img/rett.png') no-repeat 0 0
.icon-deals
@extend %icons
&:before
width: 25px
height: 25px
background: url('#{$static}/img/rett.png') no-repeat 0 -19px
.icon-reviews
@extend %icons
&:before
width: 26px
height: 26px
background: url('#{$static}/img/rett.png') no-repeat 0 -44px
.icon-protect
@extend %icons
&:before
width: 26px
height: 26px
background: url('#{$static}/img/cenaList.png') no-repeat 0 0
.icon-trash-red
@extend %icons
&:before
width: 21px
height: 21px
background: url('#{$static}/img/cenaList3.png') no-repeat 0 0
.icon-trash-gray
@extend %icons
&:before
width: 21px
height: 21px
background: url('#{$static}/img/cenaList3.png') no-repeat 0 0
.icon-calendar
@extend %icons
&:before
width: 19px
height: 19px
background: url('#{$static}/img/listPro.png') no-repeat 0 0
.icon-eye
@extend %icons
&:before
width: 26px
height: 18px
background:
image: url('#{$static}/img/icons/icon_eye.png')
repeat: no-repeat
size: 26px 18px
.icon-speach-ball_gray
@extend %icons
&:before
width: 18px
height: 18px
background:
image: url('#{$static}/img/icons/icon_speach-ball_gray.png')
repeat: no-repeat
size: 18px 18px
.icon-certificate
@extend %icons
&:before
width: 18px
height: 18px
background:
image: url('#{$static}/img/icons/icon_сertificate-512.png')
repeat: no-repeat
size: 18px 18px

@ -0,0 +1,42 @@
{% extends 'partials/_base.html' %}
{% load staticfiles %}
{% load sass_tags %}
{% block personal_css %}
<link rel='stylesheet' href='{% sass_src "sass/customer-profile.sass" %}'>
<link rel='stylesheet' href='{% sass_src "sass/old_main.sass" %}'>
<link rel='stylesheet' href='{% sass_src "sass/components/custom-components.sass" %}'>
{# <link rel='stylesheet' href='{% static "css/main.css" %}'>#}
{% endblock %}
{% block content %}
<div class="container main-scope">
<div class="row main-content">
<div class="col-lg-12">
{% include 'partials/inc-customer_profile-info.html' %}
<div class="row">
<div class="col-lg-12">
<div class="tab-content">
<div id="objects" class="tab-pane fade in active">
{% include 'partials/tabs/tab-objects.html' %}
</div>
<div id="open_projects" class="tab-pane fade">
{% include 'partials/tabs/tab-open_projects.html' %}
</div>
<div id="in_work_projects" class="tab-pane fade">
{% include 'partials/tabs/tab-in_work_projects.html' %}
</div>
<div id="rewiews" class="tab-pane fade">
{% include 'partials/tabs/tab-rewiews.html' %}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block personal_js %}
<script src="{% static 'js/build/customer_profile.js' %}"></script>
{% endblock %}

@ -0,0 +1,105 @@
{% load thumbnail %}
{% load staticfiles %}
{% load specializtions_tags %}
{% load user_tags %}
<div class="row">
<div class="col-lg-3">
<div class="avatar new-mar">
<div class="avatarInset">
{% if customer.avatar %}
{% thumbnail customer.avatar "235x224" crop="center" as im %}
<img src="{{ im.url }}" alt="profile-image">
{% endthumbnail %}
{% else %}
<img src="{% static 'img/profile.jpg' %}" alt="profile-image">
{% endif %}
</div>
</div>
</div>
<div class="col-lg-9">
<div class="row mod-row-eq-height" style="padding-bottom: 40px">
<div class="col-lg-5">
<span class="user_name">{{ customer.get_full_name }} <br>[{{ customer.username }}]</span>
<table style="margin-top: 10px; margin-bottom: 10px">
<tr>
<td style="min-width: 100px">На сайте:</td>
<td>{{ customer.created }}</td>
</tr>
<tr>
<td>Страна:</td>
<td>{{ customer.country }}</td>
</tr>
<tr>
<td>Город:</td>
<td>{{ customer.city }}</td>
</tr>
</table>
{% if request.user == customer %}
<a href="{% url 'users:user-profile-edit' pk=pk %}" class="btn btn-simple mod-align-center-inline"
style="padding: px 20px; font-size: 12pt">
<span type="submit" class="icon-edit"> </span> редактировать профиль
</a>
{% endif %}
</div>
<div class="col-lg-7" style="border-bottom: 1px solid gainsboro; border-top: 1px solid gainsboro">
<table class="ratings" style="float: right">
<tr>
<td>
<div class="icon-rating">Рейтинг:</div>
</td>
<td>
<span> {{ ratings }}</span>
</td>
</tr>
<tr>
<td>
<div class="icon-deals">Безопасные сделки:</div>
</td>
<td>
<span> {{ deals }}</span>
</td>
</tr>
<tr>
<td>
<div class="icon-reviews">Отзывы:</div>
</td>
<td>
<span class="positive"> {{ reviews_p }}</span>
<span class="neutral"> {{ reviews_n }}</span>
<span class="negative"> {{ reviews_m }}</span>
</td>
</tr>
</table>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="profileTabs2 tabs-new">
<ul class="nav nav-tabs nav-justified">
<li class="active">
<a data-toggle="tab" href="#objects">
<div class="mod-align-center-inline"> Объекты <span class="count">{{ objects.count }}</span></div>
</a>
</li>
<li>
<a data-toggle="tab" href="#open_projects">
<div class="mod-align-center-inline"> Открытые заказы <span class="count">{{ open_projects.count }}</span></div>
</a>
</li>
<li>
<a data-toggle="tab" href="#in_work_projects">
<div class="mod-align-center-inline"> Заказы в работе <span class="count">{{ projects_in_work.count }}</span></div>
</a>
</li>
<li>
<a data-toggle="tab" href="#rewiews">
<div class="mod-align-center-inline"> Отзывы <span class="count">{{ reviews.count }}</span></div>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>

@ -0,0 +1,114 @@
{% for object in objects %}
<div class="row object">
<div class="separator">
<div class="border add_line"></div>
</div>
<div style="margin-bottom: 15px" class="row">
<div class="col-lg-9">
<div class="object-header">{{ object.name }}</div>
</div>
{% if request.user == customer %}
<div class="col-lg-3">
{% if trash %}
<form action="{% url 'customer-object-restore' pk=object.pk %}" method="POST">
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}">
<a href='#' onclick="$(this).closest('form').submit(); return false">
<span class="icon-protect">Восстановить</span>
</a>
</form>
{% else %}
<span class="icon-protect">Редактировать</span>
{% endif %}
</div>
{% endif %}
</div>
<div class="row mod-align-center">
<div class="col-lg-9">
Заказы: <span class="projects_count"> {{ object.projects.count }}</span>
<button class="bnt btn-default btn-up_down -small" type="submit"
value="num_orders"
onclick="toggler(this, 'obj-{{ object.id }}')">
<span class="text">Посмотреть</span>
</button>
{% if request.user == customer %}
<a href="{% url 'projects:customer-project-create' %}"
class="btn btn-simple -small">
Добавить заказ
</a>
{% endif %}
</div>
<div class="col-lg-3">
{% if request.user == customer %}
{% if trash %}
<form action="{% url 'customer-object-delete' pk=object.pk %}" method="POST">
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}">
<a href='#' onclick="$(this).closest('form').submit(); return false">
<span class="icon-trash-red">Удалить навсегда</span>
</a>
</form>
{% else %}
<form action="{% url 'customer-object-trash' pk=object.pk %}"
method="POST" novalidate>
{% csrf_token %}
<input type="hidden" name="next"
value="{{ request.path }}">
<a href="#"
onclick="$(this).closest('form').submit(); return false">
<span class="icon-trash-red">Переместить в корзину</span>
</a>
</form>
{% endif %}
{% endif %}
</div>
</div>
<div class="row" id="obj-{{ object.id }}" style="display: none">
<div class="col-lg-12">
<div class="separator">
<div class="border"></div>
</div>
<table class="projects">
{% for project in object.projects.all %}
<tr>
<td><strong>{{ forloop.counter }}</strong></td>
<td>{{ project.name }}</td>
<td>
<span class="icon-calendar">{{ project.created }}</span>
</td>
<td>
<span class="icon-eye">{{ project.hit_count.hits }}</span>
</td>
<td>
<span class="icon-speach-ball_gray">{{ project.message_count }}</span>
</td>
{# <td>{{ project.answers.count }}</td>#}
<td>
<span class="icon-certificate">
<span class="cut">{{ project.specialization.full_path }}</span>
</span>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
</div>
<span style="margin: 10px 0" class="icon-calendar">
{{ object.created }}
</span>
{% endfor %}
<div class="row">
<div class="separator">
<div class="border"></div>
</div>
</div>

@ -0,0 +1,99 @@
{% load project_tags %}
<div class="projectsBlock new-pro-block disTab">
{% for proj in open_projects %}
<div class="projectPro clearfix">
<div class="col-lg-9 leftPro">
<p class="titlePro">
<a href="{% url 'projects:detail' proj.pk %}">{{ proj.name }}</a>
</p>
<ul class="desPro">
<li>Объект "{{ proj.realty.name }}"</li>
<li><span>{{ proj.get_team_answers|length }}</span> ответ от имени
группы
</li>
</ul>
{% if request.user == customer %}
<ul class="color-menu">
<li>
<a href="{% url 'projects:detail' proj.pk %}#new-answers">Новые: {{ proj|get_new_answers|length }}</a>
</li>
<li>
<a href="{% url 'projects:detail' proj.pk %}#candidate-answers">Кандидаты: {{ proj|get_candidate_answers|length }}</a>
</li>
<li>
<a href="{% url 'projects:detail' proj.pk %}#rejected-answers">Отказал: {{ proj|get_rejected_answers|length }}</a>
</li>
</ul>
{% endif %}
<p class="textPro">
{{ proj.text }}
</p>
<ul class="listPro">
<li>{{ proj.created }}</li>
<li>{{ proj.hit_count.hits }}</li>
<li>{{ proj.answers.count }}</li>
<li>{{ customer.get_full_name }}</li>
</ul>
</div>
<div class="col-lg-3 rightPro right-pro-red">
<p class="cenaPro">
{{ proj.budget }} <i
class="{% fa_currency_classes proj.currency %}"></i>
</p>
{% if request.user == proj.customer %}
{% if trash %}
<ul>
<li>
<form action="{% url 'projects:customer-project-restore' pk=proj.pk %}" method="POST">
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}">
<a href='#' onclick="$(this).closest('form').submit(); return false">Восстановить из
корзины</a>
</form>
</li>
<li>
<form action="{% url 'projects:customer-project-delete' pk=proj.pk %}" method="POST">
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}">
<a href='#' onclick="$(this).closest('form').submit(); return false">Удалить
навсегда</a>
</form>
</li>
</ul>
{% else %}
<ul>
<li>
<a href='{% url 'projects:customer-project-edit' pk=proj.pk %}?back={{ request.path }}'>Редактировать</a>
</li>
<li>
<form action="{% url 'projects:customer-project-trash' pk=proj.pk %}"
method="POST" novalidate>
{% csrf_token %}
<input type="hidden" name="next"
value="{{ request.path }}">
<a href="#"
onclick="$(this).closest('form').submit(); return false">Переместить
в корзину</a>
</form>
</li>
</ul>
{% endif %}
{% endif %}
</div>
</div>
{% endfor %}
</div>
<div class="col-lg-12 pagin">
{% include 'partials/pagination.html' %}
</div>

@ -0,0 +1,82 @@
{% load project_tags %}
<div class="old-main">
<div class="projectsBlock new-pro-block disTab">
{% for proj in projects_in_work %}
<div class="projectPro clearfix">
<div class="col-lg-9 leftPro">
<p class="titlePro">
<a href="{% url 'projects:detail' proj.pk %}">{{ proj.name }}</a>
</p>
<ul class="desPro">
<li>Объект "{{ proj.realty.name }}"</li>
<li><span>{{ proj.get_team_answers|length }}</span> ответ от имени
группы
</li>
</ul>
{% if request.user == customer %}
<ul class="color-menu">
<li>
<a href="{% url 'projects:detail' proj.pk %}#new-answers">Новые: {{ proj|get_new_answers|length }}</a>
</li>
<li>
<a href="{% url 'projects:detail' proj.pk %}#candidate-answers">Кандидаты: {{ proj|get_candidate_answers|length }}</a>
</li>
<li>
<a href="{% url 'projects:detail' proj.pk %}#rejected-answers">Отказал: {{ proj|get_rejected_answers|length }}</a>
</li>
</ul>
{% endif %}
<p class="textPro">
{{ proj.text }}
</p>
<ul class="listPro">
<li>{{ proj.created }}</li>
<li>{{ proj.hit_count.hits }}</li>
<li>{{ proj.answers.count }}</li>
<li>{{ customer.get_full_name }}</li>
</ul>
</div>
<div class="col-lg-3 rightPro right-pro-red">
<p class="cenaPro">
{{ proj.budget }} <i
class="{% fa_currency_classes proj.currency %}"></i>
</p>
{% if request.user == proj.customer %}
<div class="open-projects-div1">
<ul>
<li>
<a href='{% url 'projects:customer-project-edit' pk=proj.pk %}?back={{ request.path }}'>Редактировать</a>
</li>
<li>
<form action="{% url 'projects:customer-project-trash' pk=proj.pk %}"
method="POST" novalidate>
{% csrf_token %}
<input type="hidden" name="next"
value="{{ request.path }}">
<a href="#"
onclick="$(this).closest('form').submit(); return false">Переместить
в корзину</a>
</form>
</li>
</ul>
</div>
{% endif %}
</div>
</div>
{% endfor %}
</div>
<div class="col-lg-12 pagin">
{% include 'partials/pagination.html' %}
</div>
</div>

@ -0,0 +1,48 @@
<div class="row" style="margin: 35px 0">
{% if request.user == customer %}
<div class="col-lg-12">
<div class="btn-group btn-round">
<a data-toggle="tab" href="#_objects"
class="btn btn-default tab-inserted active">
Текущие объекты
<span>{{ objects.count }}</span>
</a>
<a data-toggle="tab" href="#trashed_objects"
class="btn btn-default tab-inserted">
Удаленные объекты
<span>{{ trashed_objects.count }}</span>
</a>
</div>
<a href="{% url 'projects:customer-project-create' %}"
style="float: right; letter-spacing: 4px; padding-left: 35px; padding-right: 35px"
class="btn btn-simple">
Добавить объект
</a>
</div>
{% endif %}
</div>
<div class="row">
<div class="col-lg-12">
<div class="link-sort">
Сортировать по:
{# name="name" #}
<button class="bnt btn-default" type="submit" onclick="sortRealtyBy({sortBy: 'name', user_id: '{{ customer.id }}', state: 'active'}, '#_objects')">
названию
</button>
<button class="bnt btn-default" type="submit" onclick="sortRealtyBy({sortBy: 'created', user_id: '{{ customer.id }}', state: 'active'}, '#_objects')">
дате создания
</button>
<button class="bnt btn-default" type="submit" onclick="sortRealtyBy({sortBy: 'num_orders', user_id: '{{ customer.id }}', state: 'active'}, '#_objects')">
количеству заказов
</button>
</div>
</div>
</div>
<div class="tab-content">
<div id="_objects" class="tab-pane fade in active">
{% include 'partials/inc-objects.html' with objects=objects %}
</div>
<div id="trashed_objects" class="tab-pane fade">
{% include 'partials/inc-objects.html' with objects=trashed_objects trash=1 %}
</div>
</div>

@ -0,0 +1,39 @@
<div class="old-main">
{% if request.user == customer %}
<div class="row" style="margin: 35px 0;">
<div class="col-lg-12">
<div class="btn-group btn-round">
<a data-toggle="tab" href="#_projects"
class="btn btn-default tab-inserted active">
Текущие объекты
<span>{{ open_projects.count }}</span>
</a>
{% if request.user == customer %}
<a data-toggle="tab" href="#trashed_projects"
class="btn btn-default tab-inserted">
Удаленные объекты
<span>{{ trashed_projects.count }}</span>
</a>
{% endif %}
</div>
{# <div style="display: inline-block;">#}
{# Filter be here#}
{# </div>#}
<a href="{% url 'projects:customer-project-create' %}"
style="float: right; letter-spacing: 4px; padding-left: 35px; padding-right: 35px"
class="btn btn-simple">
Разместить заказ
</a>
</div>
</div>
{% endif %}
<div class="tab-content">
<div id="_projects" class="tab-pane fade in active">
{% include 'partials/inc-projects.html' with open_projects=open_projects %}
</div>
<div id="trashed_projects" class="tab-pane fade">
{% include 'partials/inc-projects.html' with open_projects=trashed_projects trash=1 %}
</div>
</div>
</div>

@ -0,0 +1,29 @@
<div class="old-main">
{% for review in reviews %}
<div class="new-comm-44">
<div class="col-lg-12">
<p class="nameComm">
<a href="#">{{ review.from_contractor.get_full_name }}</a>
</p>
<span class="dateComm44">
{{ review.project.get_deal_type_display }}
</span>
<div class="stars box-sizing">
<a href="#">
{% if review.type == 'positive' %}
Положительный отзыв
{% elif review.type == 'negative' %}
Отрицательный отзыв
{% else %}
Нейтральный отзыв
{% endif %}
</a>
</div>
<p class="textComm44">{{ review.text }}</p>
</div>
</div>
{% endfor %}
</div>

@ -6,7 +6,7 @@
<div class="col-lg-12">
<div class="col-lg-3 divCol3">
<div class="avatar new-mar">
<div class="avatar">
<div class="avatarInset">
{% if customer.avatar %}
{% thumbnail customer.avatar "235x224" crop="center" as im %}
@ -36,7 +36,8 @@
<div class="col-lg-4">
{% if request.user.pk != customer.pk %}
<a href="javascript:void(0)" class="new-prop new-prop1">показать контакты</a>
<a href="{% url 'chat:chat-user' %}?user_id={{ pk }}#user{{ pk }}" class="new-prop new-prop2">написать сообщение</a>
<a href="{% url 'chat:chat-user' %}?user_id={{ pk }}#user{{ pk }}" class="new-prop new-prop2">написать
сообщение</a>
{% else %}
<a href="{% url 'users:user-profile-edit' pk=pk %}" class="new-red">редактировать профиль</a>
{% endif %}

@ -25,7 +25,7 @@
{% csrf_token %}
{% if request.user.is_customer %}
<input type="hidden" name="next" value="{% url 'users:customer-profile-open-projects' pk=pk %}">
<input type="hidden" name="next" value="{% url 'users:customer-profile' pk=pk %}">
{% elif request.user.is_contractor %}
<input type="hidden" name="next" value="{% url 'users:contractor-profile' pk=pk %}">
{% endif %}

@ -1,13 +1,11 @@
{% extends 'partials/base.html' %}
{% extends 'partials/_base.html' %}
{% load staticfiles %}
{% load thumbnail %}
{% load sass_tags %}
{% block head_css %}
{# <link rel='stylesheet' href='{% static "lib/proekton-components/css/fonts.css" %}'>#}
{# <link rel='stylesheet' href='{% static "lib/proekton-components/css/selected-container.css" %}'>#}
{# <link rel='stylesheet' href='{% static "lib/proekton-components/css/editable-container.css" %}'>#}
{# <link rel='stylesheet' href='{% static "lib/proekton-components/css/select-box.css" %}'>#}
{#{% block old_css %}{% endblock %}#}
{% block personal_css %}
<link rel='stylesheet' href='{% sass_src "lib/proekton-components/sass/components.sass" %}'>
<link rel='stylesheet' href='{% sass_src "sass/old_main.sass" %}'>
<link rel='stylesheet' href='{% static "css/project_filter.css" %}'>{# other #}
<link rel='stylesheet' href='{% static "css/font-awesome.min.css" %}'>
<link rel='stylesheet' href='{% static "css/user_profile_edit.css" %}'>
@ -15,20 +13,17 @@
{% endblock %}
{% block content %}
{% include 'partials/header.html' %}
{# {% if request.user.is_customer %}#}
{# <input type="hidden" name="next"#}
{# value="{% url 'users:customer-profile-open-projects' pk=pk %}">#}
{# {% elif request.user.is_contractor %}#}
{# <input type="hidden" name="next" value="{% url 'users:contractor-profile' pk=pk %}">#}
{# {% endif %}#}
<div class="container mainScore">
<div class="row mainContent">
<div class="container main-scope">
<div class="row main-content">
{# <div class="old-main">#}
<form method="POST" enctype="multipart/form-data" novalidate>
{% csrf_token %}
{% if request.user.is_customer %}
<input type="hidden" name="next" value="{% url 'users:customer-profile' pk=pk %}">
{% else %}
<input type="hidden" name="next" value="{% url 'users:contractor-profile' pk=pk %}">
{% endif %}
<div class="col-lg-12">
<div class="row row-eq-height">
<div class="col-lg-3 -live-image-avatar-upload-container">
@ -38,7 +33,7 @@
style="display: none">&times;</a>
{% if request.user.avatar %}
{% thumbnail request.user.avatar "235x224" crop="center" as avatar %}
{% thumbnail request.user.avatar "208x208" crop="center" as avatar %}
<img src="{{ avatar.url }}" alt="profile-image" class="-avatar-image">
{% endthumbnail %}
{% else %}
@ -64,10 +59,19 @@
<div class="row">
<div class="col-lg-12">
<div class="bottom-line">
{% if request.user.is_customer %}
<span class="header">
Полное заполнение профиля влияет на количество откликиков исполнителей и “безопасную сделку”
<i class="fa fa-question-circle-o" aria-hidden="true" title=""></i>
</span>
{% else %}
<span class="header">
Параметры заполнения прифоля влияют на фильтр поиска специалистов, ранжирования в списке
<i class="fa fa-question-circle-o" aria-hidden="true" title=""></i>
</span>
{% endif %}
</div>
</div>
</div>
@ -86,7 +90,8 @@
class="simple-input" placeholder="Фамилия">
</div>
<div class="col-lg-4">
<input value="{{ form.first_name.value }}" name="{{ form.first_name.html_name }}"
<input value="{{ form.first_name.value }}"
name="{{ form.first_name.html_name }}"
class="simple-input" placeholder="Имя">
</div>
<div class="col-lg-4">
@ -116,7 +121,7 @@
</div>
</div>
</div> <!-- top -->
{% if request.user.is_contractor %}
<div class="row">
<div style="padding-bottom: 10px" class="col-lg-12">
<div class="row">
@ -156,7 +161,8 @@
<div class="row">
<div class="col-lg-12">
<div class="selected-container horizontal" id="selected-spec">
<input type="hidden" name="{{ form.contractor_specializations.html_name }}"
<input type="hidden"
name="{{ form.contractor_specializations.html_name }}"
value="{{ form.contractor_specializations.value }}">
</div>
</div>
@ -177,7 +183,8 @@
<div class="vertical-child" id="sb-construction-type">
</div>
<div class="selected-container" id="selected-construction-type">
<input type="hidden" name="{{ form.contractor_construction_types.html_name }}"
<input type="hidden"
name="{{ form.contractor_construction_types.html_name }}"
value="{{ form.contractor_construction_types.value }}">
</div>
</div>
@ -198,6 +205,7 @@
</div>
</div>
</div> <!-- center -->
{% endif %}
<div class="row">
<div class="col-lg-12">
<div class="row">
@ -229,7 +237,8 @@
</div>
<input class="simple-select" placeholder="Выберите"
value="{{ form.get_gender_display }}" readonly>
<input type="hidden" name="{{ form.gender.html_name }}" value="{{ form.gender.value }}">
<input type="hidden" name="{{ form.gender.html_name }}"
value="{{ form.gender.value }}">
<div class="select-box-options" style="width: 100%; display: none">
<div style="min-width: inherit" class="box-wrapper">
<ul>
@ -250,7 +259,8 @@
</div>
<input class="simple-select" placeholder="Выберите"
value="{{ form.get_status_display }}" readonly>
<input type="hidden" name="{{ form.contractor_status.html_name }}" value="{{ form.contractor_status.value }}">
<input type="hidden" name="{{ form.contractor_status.html_name }}"
value="{{ form.contractor_status.value }}">
<div class="select-box-options" style="width: 100%; display: none">
<div style="min-width: inherit" class="box-wrapper">
<ul>
@ -264,7 +274,8 @@
</div>
<div class="col-lg-3">
<div class="header">Skype</div>
<input name="{{ form.skype.html_name }}" class="simple-input" placeholder="skype id"
<input name="{{ form.skype.html_name }}" class="simple-input"
placeholder="skype id"
value="{{ form.skype.value }}">
</div>
<div class="clearfix visible-lg"></div>
@ -298,15 +309,12 @@
</div> <!-- bottom -->
</div>
</form>
{# </div>#}
</div>
<div class="row">
{% include 'partials/footer.html' %}
</div>
</div>
{% endblock %}
{% block js_block %}
{% block personal_js %}
{{ block.super }}
<script src='{% static "lib/proekton-components/js/build/init_user_profile.js" %}'></script>
<script src='{% static "projects-filter.js" %}'></script>

@ -25,7 +25,7 @@
{% csrf_token %}
{% if request.user.is_customer %}
<input type="hidden" name="next" value="{% url 'users:customer-profile-open-projects' pk=pk %}">
<input type="hidden" name="next" value="{% url 'users:customer-profile' pk=pk %}">
{% elif request.user.is_contractor %}
<input type="hidden" name="next" value="{% url 'users:contractor-profile' pk=pk %}">
{% endif %}

@ -10,6 +10,7 @@ from .views import (
ContractorProfileView,
ContractorResumeUpdateView,
CreateTeamInvitation,
CustomerProfileView,
CustomerProfileCurrentProjectsView,
CustomerProfileOpenProjectsView,
CustomerProfileReviewsView,
@ -24,15 +25,9 @@ from .views import (
app_name = 'users'
urlpatterns = [
# urls.url(r'^(?P<pk>\d+)/edit/$', UserProfileEditView.as_view(), name='user-profile-edit'),
urls.url(r'^(?P<pk>\d+)/edit/$', UserProfileEditViewFull.as_view(), name='user-profile-edit'),
# urls.url(r'^(?P<pk>\d+)/financial-info/edit/$', UserFinancialInfoEditView.as_view(),
# name='user-financial-info-edit'),
# urls.url(r'^(?P<pk>\d+)/experience/edit/$', UserProfileEditView.as_view(), name='user-experience-edit'),
urls.url(r'^customers/(?P<pk>\d+)/$', CustomerProfileOpenProjectsView.as_view(),
name='customer-profile-open-projects'),
urls.url(r'^customers/(?P<pk>\d+)/$', CustomerProfileView.as_view(),
name='customer-profile'),
urls.url(r'^customers/(?P<pk>\d+)/trashed-projects/$', CustomerProfileTrashedProjectsView.as_view(),
name='customer-profile-trashed-projects'),
urls.url(r'^customers/(?P<pk>\d+)/current-projects/$', CustomerProfileCurrentProjectsView.as_view(),

@ -13,18 +13,18 @@ from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.db.models import Q
from django.http import HttpResponse, JsonResponse, Http404
from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic import DetailView, View, UpdateView, CreateView
from django.views.generic import DetailView, View, UpdateView, CreateView, TemplateView
_.map = _.map_;
_.filter = _.filter_
from .forms import TeamForm, ContractorResumeFilesForm, ContractorResumeForm
from .forms import TeamForm, ContractorResumeFilesForm, ContractorResumeForm, CustomerProfileForm
from .models import User, Team, ContractorResume, ContractorResumeFiles, TeamInvitation
from archilance import util
from archilance.mixins import BaseMixin
from common.mixins import ContractorRequiredMixin, NoCsrfMixin
from projects.forms import PortfolioForm
from projects.models import Order
from projects.models import Order, Realty, Project
from reviews.models import Review
from work_sell.forms import WorkSellForm
from work_sell.models import Picture
@ -130,13 +130,13 @@ class UserProfileEditViewFull(BaseMixin, View):
def post(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
specs = tuple(filter(None, re.split(r'\s|,|;', request.POST.get('contractor_specializations'))))
specs = tuple(filter(None, re.split(r'\s|,|;', request.POST.get('contractor_specializations', ''))))
request.POST.setlist('contractor_specializations', specs)
builds = tuple(filter(None, re.split(r'\s|,|;', request.POST.get('contractor_building_classifications'))))
builds = tuple(filter(None, re.split(r'\s|,|;', request.POST.get('contractor_building_classifications', ''))))
request.POST.setlist('contractor_building_classifications', builds)
constructs = tuple(filter(None, re.split(r'\s|,|;', request.POST.get('contractor_construction_types'))))
constructs = tuple(filter(None, re.split(r'\s|,|;', request.POST.get('contractor_construction_types', ''))))
request.POST.setlist('contractor_construction_types', constructs)
form = self.form_class(request.POST, request=request, instance=request.user)
@ -617,6 +617,56 @@ class ContractorOfficeProjectsView(BaseMixin, View):
return render(request, self.template_name, context)
class CustomerProfileView(BaseMixin, DetailView):
template_name = 'customer_profile.html'
model = User
context_object_name = 'customer'
def get_object(self, queryset=None):
return get_object_or_404(User, pk=self.kwargs['pk'])
def get_context_data(self, **kwargs):
context = super().get_context_data()
user_id = self.kwargs['pk']
# profile-info
context.update(
{
'ratings': User.objects.get(pk=user_id).rating,
'deals': Order.objects.filter(secure=True, contractor_id=user_id, status=1).count(),
'reviews_n': Review.objects.filter(target_contractor_id=user_id, type='neutral').count(),
'reviews_m': Review.objects.filter(target_contractor_id=user_id, type='negative').count(),
'reviews_p': Review.objects.filter(target_contractor_id=user_id, type='positive').count(),
})
# Realty
context.update({
'objects': Realty.objects.filter(user=self.kwargs['pk'], is_virtual=False, state="active"),
'trashed_objects': Realty.objects.filter(user=self.kwargs['pk'], is_virtual=False, state="trashed"),
})
customer = self.object
open_projects = customer.customer_projects.filter(state='active')
trashed_projects = customer.customer_projects.filter(state='trashed', order__contractor__isnull=True,
order__team__isnull=True)
projects_in_work = customer.customer_projects.filter(state='active').exclude(order__contractor__isnull=True,
order__team__isnull=True)
reviews = Review.objects.filter(target_customer=customer)
context.update({
'customer': customer,
'open_projects': open_projects,
'trashed_projects': trashed_projects,
'projects_in_work': projects_in_work,
'reviews': reviews,
# 'is_paginated': True,
# 'page_obj': projects,
})
return context
class CustomerProfileOpenProjectsView(BaseMixin, View):
template_name = 'customer_profile_open_projects.html'
form_class = CustomerProfileProjectRealtyForm

@ -16,6 +16,8 @@ module.exports = {
init_create_worksell: './assets/js/src/init_create_worksell.js',
//home
home_page: "./assets/js/src/home_page.js",
//profile
customer_profile: "./assets/js/src/customer_profile.js"
},

Loading…
Cancel
Save