Преглед изворни кода

Merged with feature/498

feature/625
Djordje Mitrovic пре 3 година
родитељ
комит
1cf13904fa
100 измењених фајлова са 26085 додато и 2803 уклоњено
  1. 24700
    41
      package-lock.json
  2. 7
    6
      src/AppRoutes.js
  3. 0
    48
      src/assets/styles/_base.scss
  4. 0
    7
      src/assets/styles/_functions.scss
  5. 0
    81
      src/assets/styles/_mixins.scss
  6. 0
    244
      src/assets/styles/_overwrite.scss
  7. 0
    127
      src/assets/styles/_reset.scss
  8. 0
    57
      src/assets/styles/_typography.scss
  9. 0
    72
      src/assets/styles/_variables.scss
  10. 0
    60
      src/assets/styles/components/_app-button.scss
  11. 0
    45
      src/assets/styles/components/_auth-card.scss
  12. 0
    23
      src/assets/styles/components/_auth.scss
  13. 0
    173
      src/assets/styles/components/_button.scss
  14. 0
    46
      src/assets/styles/components/_error-page.scss
  15. 0
    23
      src/assets/styles/components/_forgot-password.scss
  16. 0
    7
      src/assets/styles/components/_icon-button.scss
  17. 0
    479
      src/assets/styles/components/_input.scss
  18. 0
    72
      src/assets/styles/components/_loader.scss
  19. 0
    31
      src/assets/styles/components/_login-card.scss
  20. 0
    72
      src/assets/styles/components/_login.scss
  21. 0
    169
      src/assets/styles/components/_modal.scss
  22. 0
    29
      src/assets/styles/components/_radio.scss
  23. 1
    2
      src/components/About/CheckOffersButton/CheckOffersButton.js
  24. 4
    1
      src/components/Buttons/ArrowButton/ArrowButton.styled.js
  25. 25
    63
      src/components/Cards/ChatCard/ChatCard.js
  26. 1
    36
      src/components/Cards/ChatCard/ChatCard.styled.js
  27. 1
    0
      src/components/Cards/ChatCard/ChatCommands/ChatCommands.js
  28. 1
    1
      src/components/Cards/ChatCard/ChatCommands/ChatCommands.styled.js
  29. 1
    1
      src/components/Cards/ChatCard/LittleOfferDetails/LittleOfferDetails.js
  30. 1
    2
      src/components/Cards/ChatCard/MobileOfferDetails/MobileOfferDetails.js
  31. 1
    0
      src/components/Cards/ChatCard/OfferLocation/OfferLocation.js
  32. 1
    1
      src/components/Cards/CreateOfferCard/BackButton/BackButton.js
  33. 49
    73
      src/components/Cards/CreateOfferCard/CreateOffer.js
  34. 23
    3
      src/components/Cards/CreateOfferCard/CreateOffer.styled.js
  35. 50
    205
      src/components/Cards/CreateOfferCard/FirstPart/FirstPartCreateOffer.js
  36. 0
    55
      src/components/Cards/CreateOfferCard/FirstPart/FirstPartCreateOffer.styled.js
  37. 44
    0
      src/components/Cards/CreateOfferCard/FirstPart/NextButton/NextButton.js
  38. 0
    0
      src/components/Cards/CreateOfferCard/FirstPart/NextButton/NextButton.styled.js
  39. 45
    0
      src/components/Cards/CreateOfferCard/FirstPart/OfferCategoryField/OfferCategoryField.js
  40. 0
    0
      src/components/Cards/CreateOfferCard/FirstPart/OfferCategoryField/OfferCategoryField.styled.js
  41. 51
    0
      src/components/Cards/CreateOfferCard/FirstPart/OfferDescriptionField/OfferDescriptionField.js
  42. 15
    0
      src/components/Cards/CreateOfferCard/FirstPart/OfferDescriptionField/OfferDescriptionField.styled.js
  43. 40
    0
      src/components/Cards/CreateOfferCard/FirstPart/OfferLocationField/OfferLocationField.js
  44. 0
    0
      src/components/Cards/CreateOfferCard/FirstPart/OfferLocationField/OfferLocationField.styled.js
  45. 41
    0
      src/components/Cards/CreateOfferCard/FirstPart/OfferSubcategoryField/OfferSubcategoryField.js
  46. 0
    0
      src/components/Cards/CreateOfferCard/FirstPart/OfferSubcategoryField/OfferSubcategoryField.styled.js
  47. 33
    0
      src/components/Cards/CreateOfferCard/FirstPart/OfferTitleField/OfferTitleField.js
  48. 14
    0
      src/components/Cards/CreateOfferCard/FirstPart/OfferTitleField/OfferTitleField.styled.js
  49. 37
    0
      src/components/Cards/CreateOfferCard/SecondPart/NextButton/NextButton.js
  50. 0
    0
      src/components/Cards/CreateOfferCard/SecondPart/NextButton/NextButton.styled.js
  51. 47
    0
      src/components/Cards/CreateOfferCard/SecondPart/OfferConditionField/OfferConditionField.js
  52. 10
    0
      src/components/Cards/CreateOfferCard/SecondPart/OfferConditionField/OfferConditionField.styled.js
  53. 29
    0
      src/components/Cards/CreateOfferCard/SecondPart/OfferImagePicker/OfferImagePicker.js
  54. 8
    0
      src/components/Cards/CreateOfferCard/SecondPart/OfferImagePicker/OfferImagePicker.styled.js
  55. 38
    114
      src/components/Cards/CreateOfferCard/SecondPart/SecondPartCreateOffer.js
  56. 0
    14
      src/components/Cards/CreateOfferCard/SecondPart/SecondPartCreateOffer.styled.js
  57. 23
    17
      src/components/Cards/CreateOfferCard/ThirdPart/ThirdPartCreateOffer.js
  58. 0
    2
      src/components/Cards/FilterCard/FilterCard.js
  59. 0
    68
      src/components/Cards/FilterCard/Mockupdata.js
  60. 4
    5
      src/components/Cards/FilterCard/Skeleton/SkeletonChooserHeader/SkeletonChooserHeader.js
  61. 2
    3
      src/components/Cards/FilterCard/Skeleton/SkeletonChooserTitle/SkeletonChooserTitle.js
  62. 11
    12
      src/components/Cards/FilterCard/Skeleton/SkeletonFilterCard.js
  63. 1
    2
      src/components/Cards/FilterCard/Skeleton/SkeletonSection/SkeletonSection.js
  64. 4
    5
      src/components/Cards/FilterCard/Skeleton/SkeletonSection/SkeletonSectionOption/SkeletonSectionOption.js
  65. 0
    1
      src/components/Cards/LittleOfferCard/LittleOfferCard.js
  66. 0
    1
      src/components/Cards/MessageCard/MessageCard.js
  67. 8
    4
      src/components/Cards/MiniChatCard/MiniChatCard.js
  68. 36
    0
      src/components/Cards/OfferCard/CheckButton/CheckButton.js
  69. 18
    0
      src/components/Cards/OfferCard/CheckButton/CheckButton.styled.js
  70. 28
    0
      src/components/Cards/OfferCard/DeleteOffer/CancelButton/CancelButton.js
  71. 9
    0
      src/components/Cards/OfferCard/DeleteOffer/CancelButton/CancelButton.styled.js
  72. 10
    43
      src/components/Cards/OfferCard/DeleteOffer/DeleteOffer.js
  73. 0
    46
      src/components/Cards/OfferCard/DeleteOffer/DeleteOffer.styled.js
  74. 35
    0
      src/components/Cards/OfferCard/DeleteOffer/OfferDescription/OfferDescription.js
  75. 37
    0
      src/components/Cards/OfferCard/DeleteOffer/OfferDescription/OfferDescription.styled.js
  76. 29
    0
      src/components/Cards/OfferCard/DeleteOffer/SaveButton/SaveButton.js
  77. 9
    0
      src/components/Cards/OfferCard/DeleteOffer/SaveButton/SaveButton.styled.js
  78. 10
    23
      src/components/Cards/OfferCard/OfferCard.js
  79. 1
    44
      src/components/Cards/OfferCard/OfferCard.styled.js
  80. 26
    0
      src/components/Cards/OfferCard/OfferDescription/OfferDescription.js
  81. 33
    0
      src/components/Cards/OfferCard/OfferDescription/OfferDescription.styled.js
  82. 0
    1
      src/components/Cards/OfferCard/SkeletonOfferCard/SkeletonOfferCard.js
  83. 25
    0
      src/components/Cards/ProfileCard/EditProfile/AppLinkField/AppLinkField.js
  84. 0
    0
      src/components/Cards/ProfileCard/EditProfile/AppLinkField/AppLinkField.styled.js
  85. 167
    0
      src/components/Cards/ProfileCard/EditProfile/EditProfile.js
  86. 4
    35
      src/components/Cards/ProfileCard/EditProfile/EditProfile.styled.js
  87. 27
    0
      src/components/Cards/ProfileCard/EditProfile/FirmNameField/FirmNameField.js
  88. 0
    0
      src/components/Cards/ProfileCard/EditProfile/FirmNameField/FirmNameField.styled.js
  89. 28
    0
      src/components/Cards/ProfileCard/EditProfile/FormikErrorMessage/FormikErrorMessage.js
  90. 11
    0
      src/components/Cards/ProfileCard/EditProfile/FormikErrorMessage/FormikErrorMessage.styled.js
  91. 42
    0
      src/components/Cards/ProfileCard/EditProfile/LocationField/LocationField.js
  92. 25
    0
      src/components/Cards/ProfileCard/EditProfile/LocationField/LocationField.styled.js
  93. 29
    0
      src/components/Cards/ProfileCard/EditProfile/PIBField/PIBField.js
  94. 0
    0
      src/components/Cards/ProfileCard/EditProfile/PIBField/PIBField.styled.js
  95. 39
    0
      src/components/Cards/ProfileCard/EditProfile/PhoneField/PhoneField.js
  96. 0
    0
      src/components/Cards/ProfileCard/EditProfile/PhoneField/PhoneField.styled.js
  97. 29
    0
      src/components/Cards/ProfileCard/EditProfile/WebsiteField/WebsiteField.js
  98. 0
    0
      src/components/Cards/ProfileCard/EditProfile/WebsiteField/WebsiteField.styled.js
  99. 7
    8
      src/components/Cards/ProfileCard/ProfileCard.js
  100. 0
    0
      src/components/Cards/ProfileCard/ProfileCard.styled.js

+ 24700
- 41
package-lock.json
Разлика између датотеке није приказан због своје велике величине
Прегледај датотеку


+ 7
- 6
src/AppRoutes.js Прегледај датотеку

@@ -41,20 +41,21 @@ import ChatPage from "./pages/Chat/Chat";
import MyOffers from "./pages/MyOffers/MyOffers";
// import PricesPage from "./pages/Prices/PricesPage";
import AboutPage from "./pages/About/AboutPage";
import AuthRoute from "./components/Router/AuthRoute";
// import PrivacyPolicyPage from "./pages/PrivacyPolicy/PrivacyPolicyPage";

const AppRoutes = () => {
return (
<Switch>
<Route exact path={BASE_PAGE} component={HomePage} />
<Route exact path={LOGIN_PAGE} component={LoginPage} />
<AuthRoute exact path={LOGIN_PAGE} component={LoginPage} />
<Route path={NOT_FOUND_PAGE} component={NotFoundPage} />
<Route path={REGISTER_SUCCESSFUL_PAGE} component={RegisterSuccessful} />
<Route path={REGISTER_PAGE} component={Register} />
<Route path={ERROR_PAGE} component={ErrorPage} />
<Route path={FORGOT_PASSWORD_MAIL_SENT} component={MailSent} />
<Route path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} />
<Route path={RESET_PASSWORD_PAGE} component={ResetPasswordPage} />
<AuthRoute path={REGISTER_SUCCESSFUL_PAGE} component={RegisterSuccessful} />
<AuthRoute path={REGISTER_PAGE} component={Register} />
<AuthRoute path={FORGOT_PASSWORD_MAIL_SENT} component={MailSent} />
<AuthRoute path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} />
<AuthRoute path={RESET_PASSWORD_PAGE} component={ResetPasswordPage} />
<Route path={CREATE_OFFER_PAGE} component={CreateOffer} />
<Route path={ITEM_DETAILS_PAGE} component={ItemDetailsPage} />
<Route path={PROFILE_PAGE} component={ProfilePage} />

+ 0
- 48
src/assets/styles/_base.scss Прегледај датотеку

@@ -1,48 +0,0 @@
body {
margin: 0;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
overflow-anchor: none;
background-color: #F1F1F1;
}

* {
box-sizing: border-box;
font-family: "DM Sans";
}

html {
min-height: 100%;
font-size: 16px;

@include media-below($bp-xxl) {
font-size: 14px;
}

@include media-below($bp-xs) {
font-size: 13px;
}

@include media-below($bp-xxs) {
font-size: 10.5px;
}
}

html,
body,
#root {
@include flex-column;
flex: 1 0 auto;
}

input[type='search']::-webkit-search-decoration,
input[type='search']::-webkit-search-cancel-button,
input[type='search']::-webkit-search-results-button,
input[type='search']::-webkit-search-results-decoration {
-webkit-appearance: none;
}

ul {
list-style: none;
padding: 0;
}

+ 0
- 7
src/assets/styles/_functions.scss Прегледај датотеку

@@ -1,7 +0,0 @@
// @function pxToRem($target, $context: $base-font-size) {
// @return ($target / $context) * 1rem;
// }

// @function pxToRemMd($target, $context: $base-font-size-md) {
// @return calc($target / $context) * 1rem;
// }

+ 0
- 81
src/assets/styles/_mixins.scss Прегледај датотеку

@@ -1,81 +0,0 @@
// @mixin desktop {
// @media (min-width: 1280px) {
// @content;
// }
// }

// @mixin desktop-lg {
// @media (min-width: 1480px) {
// @content;
// }
// }

// @mixin tablet {
// @media (max-width: 1024px) {
// @content;
// }
// }

// @mixin media-up($media) {
// @media only screen and (min-width: $media) {
// @content;
// }
// }

// @mixin media-below($media) {
// @media only screen and (max-width: #{$media - 0.02px}) {
// @content;
// }
// }

// @mixin media-between($mediaMin, $mediaMax) {
// @media screen and (min-width: $mediaMin) and (max-width: #{$mediaMax - 0.02px}) {
// @content;
// }
// }

// @mixin flex-center {
// display: flex;
// justify-content: center;
// align-items: center;
// }

// @mixin flex-column {
// display: flex;
// flex-direction: column;
// }

// @mixin button-clear {
// border: none;
// padding: 0;
// background-color: transparent;
// }

// @mixin outline-none {
// &,
// &:active,
// &:focus {
// outline: none;
// }
// }

// @mixin reset-position {
// position: relative;
// top: initial;
// left: initial;
// right: initial;
// bottom: initial;
// }

// @mixin text-ellipsis {
// white-space: nowrap;
// overflow: hidden;
// text-overflow: ellipsis;
// }

// @mixin line-clamp($lines) {
// display: -webkit-box;
// -webkit-line-clamp: $lines;
// -webkit-box-orient: vertical;
// overflow: hidden;
// }

+ 0
- 244
src/assets/styles/_overwrite.scss Прегледај датотеку

@@ -1,244 +0,0 @@
// Overwrite
.ais-ClearRefinements-button {
color: $grey-11;
font-size: pxToRem(14px);
letter-spacing: 0;
line-height: 1.15;
background-color: transparent;
border: none;
text-decoration: underline;
position: relative;
transition: all 0.2s;
outline: none;
cursor: pointer;

&[disabled] {
pointer-events: none;
opacity: 0.5;
cursor: auto;
}

&:hover {
color: $color-primary-light;
}

&:active {
color: $color-primary-dark;
}
}

.ais-RefinementList {
margin-bottom: pxToRem(32px);
margin-left: pxToRem(16px);

&.c-filter__refinement--closed {
display: none;
}
}

.ais-RefinementList.expanded {
.ais-RefinementList-showMore::before {
transform: rotate(180deg);
}
}

.ais-RefinementList-showMore {
color: $color-primary;
font-size: pxToRem(14px);
font-weight: 600;
letter-spacing: 0;
line-height: 1.56;
text-align: center;
background-color: transparent;
border: none;
position: relative;
margin-left: pxToRem(20px);
outline: none;
transition: all ease-in-out 0.3s;
cursor: pointer;

&[disabled] {
display: none;
}

&:hover {
color: $color-primary-light;
}

&:active {
color: $color-primary-dark;
}

&::before {
content: '';
background-image: url('../images/chevron-down.svg');
fill: $color-primary;
-webkit-text-stroke-color: $color-primary;
background-position: center;
width: pxToRem(20px);
height: pxToRem(20px);
position: absolute;
left: pxToRem(-22px);
transition: all 0.2s;
}
}

.ais-SearchBox {
display: flex;
justify-content: flex-end;
margin-bottom: pxToRem(24px);
}

.ais-SearchBox-input {
border: none;
color: $blue;
font-size: pxToRem(16px);
letter-spacing: 0;
line-height: 1.5;
outline: none;
-moz-appearance: none;
-webkit-appearance: none;
flex-grow: 1;

&::placeholder {
color: $blue;
font-size: pxToRem(16px);
}

@include media-below($bp-xl) {
font-size: pxToRemMd(16px);

&::placeholder {
font-size: pxToRemMd(16px);
}
}
}

.ais-SearchBox-form {
border: 1px solid $grey-6;
border-radius: $border-radius;
overflow: hidden;
padding: 0 pxToRem(12px);
height: pxToRem(33px);
align-items: center;
display: flex;
justify-content: space-between;
min-width: pxToRem(340px);
}

.ais-SearchBox-submit,
.ais-SearchBox-reset {
border: none;
background: transparent;
outline: none;
height: pxToRem(16px);

> svg {
color: $blue-1;
fill: $blue-1;
}
}

.ais-SearchBox-submitIcon {
width: pxToRem(14px);
height: pxToRem(14px);
color: $blue-1;
fill: $blue-1;
}

.ais-SearchBox-resetIcon {
width: pxToRem(14px);
height: pxToRem(14px);
}

.ais-SearchBox-reset {
margin-left: pxToRem(10px);
cursor: pointer;
}

.c-plaid-link {
padding: 0 !important;
background: transparent !important;
border-width: 0 !important;
border-radius: 0 !important;
box-shadow: $box-shadow !important;

&.c-plaid-link--select-card {
margin-top: pxToRem(40px);

.c-select-card__button {
margin-top: 0;
}
}
}

.ais-InfiniteHitsWrap {
min-height: pxToRem(200px);
}

.ais-Highlight-highlighted {
background: #fff1d6;
font-style: normal;
}

.acsb-trigger {
display: none !important;
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
}

.ais-CurrentRefinements-list {
display: flex;
flex-wrap: wrap;

> :not(:last-child) {
margin-right: pxToRem(16px);
}
}

.ais-CurrentRefinements-item {
border-radius: $border-radius;
background-color: $dark-blue;
padding: pxToRem(4px) pxToRem(8px);
flex-shrink: 0;
margin-bottom: pxToRem(16px);
}

.ais-CurrentRefinements-item-link {
font-size: pxToRem(16px);
line-height: 1.5;
font-weight: 600;
color: $white;
display: flex;
align-items: center;
text-decoration: none;
}

.ais-CurrentRefinements-close {
color: $white;
width: pxToRem(24px);
margin-left: pxToRem(8px);
}

.recharts-surface {
overflow: visible;
}

.recharts-cartesian-axis-tick-value {
color: #9aa1a9;
font-size: 10px;
letter-spacing: 0;
line-height: 20px;
}
.recharts-tooltip-wrapper:empty{
display: 'none',
}
.recharts-text{
&.recharts-pie-label-text{
font-size: 14px;
@include media-below($bp-xl) {
font-size: 12px;
}
}
}

+ 0
- 127
src/assets/styles/_reset.scss Прегледај датотеку

@@ -1,127 +0,0 @@
/**
* Reset
*
*/

*,
*:before,
*:after {
box-sizing: border-box;
}

*,
body,
button,
input,
textarea,
select {
text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale;
}

body,
div,
dl,
dt,
dd,
ul,
ol,
li,
h1,
h2,
h3,
h4,
h5,
h6,
pre,
form,
fieldset,
button,
input,
textarea,
p,
blockquote,
th,
td {
margin: 0;
padding: 0;
}

table {
border-collapse: collapse;
border-spacing: 0;
}

fieldset,
img {
border: 0;
}

address,
caption,
cite,
code,
dfn,
em,
th,
var {
font-style: normal;
font-weight: normal;
}

strong {
font-weight: 800;
}

ol,
ul {
list-style: none;
}

caption,
th {
text-align: left;
}

q:before,
q:after {
content: '';
}

abbr,
acronym {
border: 0;
}

svg {
flex-shrink: 0;
}

textarea,
input:matches([type='email'], [type='number'], [type='password'], [type='search'], [type='tel'], [type='text'], [type='url']) {
-webkit-appearance: none;

&::-webkit-autofill,
&::-webkit-contacts-auto-fill-button,
&::-webkit-credentials-auto-fill-button {
visibility: hidden;
user-select: none;
display: none !important;
position: absolute;
}
}

input[type='number']::-webkit-inner-spin-button,
input[type='number']::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;

&::-webkit-autofill,
&::-webkit-contacts-auto-fill-button,
&::-webkit-credentials-auto-fill-button {
visibility: hidden;
user-select: none;
display: none !important;
position: absolute;
}
}

+ 0
- 57
src/assets/styles/_typography.scss Прегледај датотеку

@@ -1,57 +0,0 @@
body,
div,
dl,
dt,
dd,
ul,
ol,
li,
h1,
h2,
h3,
h4,
h5,
h6,
pre,
form,
fieldset,
button,
input,
textarea,
p,
blockquote,
th,
td {
font-family: $font-family;
}

p {
vertical-align: middle;
display: inline-block;
word-break: break-word;
font-size: pxToRem(16px);
line-height: 1.5;

@include media-below($bp-md) {
font-size: pxToRemMd(16px);
}
}

a {
font-size: inherit;
line-height: inherit;
color: inherit;
}

strong {
font-weight: bold;
}

h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: 500;
}

+ 0
- 72
src/assets/styles/_variables.scss Прегледај датотеку

@@ -1,72 +0,0 @@
$base-font-size: 16px;
$base-font-size-md: 14px;

$font-family: 'Avenir Next';

// Colors
$color-primary: #024f86;
$color-primary-light: #024f86;
$color-primary-dark: #003246;
$yellow: #ffeac1;
$white: #ffffff;
$grey: #f4f4f4;
$grey-1: #ccced0;
$grey-2: #fafafa;
$grey-3: #c2c5c6;
$grey-4: #d8d8d8;
$grey-5: #808285;
$grey-6: #c9d6db;
$grey-7: rgba(128, 130, 133, 0.5);
$grey-8: rgba(201, 214, 219, 0.25);
$grey-9: #ebeff2;
$grey-10: #f0f5f6;
$grey-11: #8b8b8b;
$grey-12: #b0bfc540;
$grey-13: #9d9ea4;
$grey-14: #f7fafa;
$grey-15: #ebf2f2;
$dark-blue: #003246;
$blue: #4e7a8c;
$blue-1: #6e8fae;
$blue-2: #024f86;
$blue-3: #0f85ec;
$blue-4: #5c7e9f;
$blue-5: #dde5e7;
$black: #000;
$black-1: rgba(0, 0, 0, 0.3);
$black-2: rgba(32, 38, 43, 0.9);
$black-4: #172029;
$black-5: #272727;
$black-6: #1d2731;
$red: #ff5028;
$success: #09846b;
$success-1: #00876a;
$success-2: #008a68;

// Shadow
$button-shadow-hover: 0 5px 6px 0 rgba(112, 120, 135, 0.24);
$button-shadow-pressed: 0 2px 4px 0 rgba(112, 120, 135, 0.24);
$box-shadow: 0 3px 8px 0 rgba(112, 120, 135, 0.24);
$account-dropdown-shadow: 0 6px 38px 0 rgba(112, 120, 135, 0.56);

// Border Radius
$border-radius: 4px;
$border-radius-md: 8px;

// Breakpoints
$bp-xxs: 325px;
$bp-xs: 400px;
$bp-sm: 576px;
$bp-md: 768px;
$bp-lg: 992px;
$bp-xl: 1200px;
$bp-xxl: 1350px;

// z-index
$index-xxs: 1;
$index-xs: 2;
$index-sm: 3;
$index-md: 4;
$index-lg: 5;
$index-xl: 6;
$index-xxl: 7;

+ 0
- 60
src/assets/styles/components/_app-button.scss Прегледај датотеку

@@ -1,60 +0,0 @@
.c-button {
display: inline-flex;
align-items: center;
border-radius: $border-radius;
background-color: $color-primary;
box-shadow: 0 2px 4px 0 rgba(112, 120, 135, 0.24);
border: transparent;
padding: 8px 0;
color: $white;
width: 100%;
text-align: center;
justify-content: center;
font-family: "Avenir Next";
font-size: pxToRem(18px);
font-weight: 600;
letter-spacing: 0;
line-height: 26px;
outline: none;
text-transform: uppercase;
transition: all 0.3s ease-in-out;
cursor: pointer;

&.c-button--clean {
background: transparent;
border: 1px solid $color-primary;
color: $color-primary;

&:hover {
border-color: $color-primary-light;
color: $color-primary-light;
background-color: transparent;
}

&:active {
border-color: $color-primary-dark;
color: $color-primary-dark;
}
}

&.c-button--dropdown {
justify-content: flex-end;
padding: 8px 14px;
background-image: url("../../images/down.svg");
background-repeat: no-repeat;
background-position: 8% 50%;
}

&[disabled] {
pointer-events: none;
opacity: 0.5;
}

&:hover {
background-color: $color-primary-light;
}

&:active {
background-color: $color-primary-dark;
}
}

+ 0
- 45
src/assets/styles/components/_auth-card.scss Прегледај датотеку

@@ -1,45 +0,0 @@
.c-auth-card {
max-width: pxToRem(624px);
width: 100%;
box-shadow: $box-shadow;
border-radius: $border-radius;
border: 1px solid $color-primary-light;
padding: pxToRem(24px) pxToRem(40px) pxToRem(32px);

@include media-below($bp-md) {
border: none;
box-shadow: none;
padding: 0;
max-width: 100%;

.c-auth-card__title {
text-align: left;
font-size: pxToRemMd(36px);
margin-bottom: pxToRemMd(6px);
}

.c-auth-card__subtitle {
font-size: pxToRemMd(16px);
text-align: left;
}
}
}

.c-auth-card__title {
text-align: left;
font-size: pxToRem(36px);
line-height: 1.22;
color: $dark-blue;
font-weight: 400;
margin-bottom: pxToRem(16px);
}

.c-auth-card__subtitle {
font-size: pxToRem(16px);
line-height: 1.5;
letter-spacing: 0;
color: $color-primary;
text-align: left;
width: 100%;
font-weight: 600;
}

+ 0
- 23
src/assets/styles/components/_auth.scss Прегледај датотеку

@@ -1,23 +0,0 @@
.c-auth {
@include flex-center;
flex-direction: column;
padding-bottom: pxToRem(56px);

@include media-below($bp-md) {
padding: 0 pxToRemMd(24px) pxToRemMd(92px);

.c-auth__title {
margin: pxToRemMd(48px) auto;
font-size: pxToRemMd(24px);
line-height: 1.35;
}
}
}

.c-auth__title {
margin: pxToRem(56px) auto pxToRem(80px);
font-size: pxToRem(36px);
line-height: 1.22;
color: $dark-blue;
font-weight: bold;
}

+ 0
- 173
src/assets/styles/components/_button.scss Прегледај датотеку

@@ -1,173 +0,0 @@
.c-btn {
@include outline-none;
@include button-clear;
@include flex-center;
font-size: pxToRem(18px);
line-height: 1.35;
padding: pxToRem(8px) pxToRem(8px);
border-radius: $border-radius;
box-shadow: $button-shadow-pressed;
color: inherit;
font-weight: 600;
letter-spacing: 0;
text-align: center;
text-transform: uppercase;
user-select: none;
white-space: nowrap;
min-width: pxToRem(120px);
flex-shrink: 0;
cursor: pointer;
transition: background-color 0.2s, color 0.2s;

&:disabled {
opacity: 0.5;
cursor: auto;
}

&.c-btn--primary {
background-color: $color-primary;
color: $white;
border: 1px solid $color-primary;

&:disabled {
&:hover {
background-color: $color-primary;
box-shadow: none;
}
}

&:hover {
background-color: $color-primary-light;
box-shadow: $button-shadow-hover;
}

&:focus,
&:active {
background-color: $color-primary-dark;
box-shadow: $button-shadow-pressed;
}
}

&.c-btn--primary-outlined {
background-color: transparent;
color: $color-primary;
border: 1px solid $color-primary;

&:disabled {
&:hover {
color: $color-primary;
border: 1px solid $color-primary;
}
}

&:hover {
color: $color-primary;
border: 1px solid $color-primary;
}

&:focus,
&:active {
color: $color-primary;
border: 1px solid $color-primary;
}
}

&.c-btn--blue {
background-color: $blue-3;
color: $white;
background-color: $blue-3;
}

&.c-btn--white {
background-color: $white;
color: $grey-3;
border: 1px solid $grey-4;
box-shadow: $box-shadow;

&:disabled {
&:hover {
background-color: $white;
color: $grey-3;
}
}

&:hover {
color: $grey-5;
}

&:focus,
&:active {
background-color: $grey;
}
}

&.c-btn--primary-clear {
background-color: transparent;
color: $color-primary;
border: none;
box-shadow: none;
padding: 0;
}

&.c-btn--auto {
min-width: auto;
}

&.c-btn--sm {
font-size: pxToRem(16px);
line-height: 1.5;
padding: pxToRem(4px) pxToRem(15px);
}

&.c-btn--capitalize {
text-transform: capitalize;
}

&.c-btn--bank-acount-card {
padding: 0 pxToRem(16px);
min-height: pxToRem(32px);
min-width: pxToRem(120px);
font-size: pxToRem(16px);
line-height: 1.5;
}

&.c-btn--hidden {
visibility: hidden;
height: 0;
}

@include media-below($bp-md) {
padding: pxToRemMd(4px) pxToRemMd(25px);
font-size: pxToRemMd(16px);
line-height: 1.5;
min-width: pxToRemMd(80px);

&.c-btn--auth {
padding: pxToRemMd(12px) pxToRemMd(25px);
line-height: 1.35;
font-size: pxToRemMd(18px);
}

&.c-btn--sm {
padding: pxToRemMd(4px) pxToRemMd(15px);
}

&.c-btn--bank-acount-card {
flex-grow: 1;
min-height: pxToRemMd(40px);
padding: pxToRemMd(8px) pxToRemMd(16px);
font-size: pxToRemMd(18px);
line-height: 1.33;
}

&.c-btn--lg {
padding: pxToRemMd(7.5px) pxToRemMd(15px);
font-size: pxToRemMd(18px);
line-height: 1.5;
}
}

@include media-below($bp-xs) {
white-space: unset;
}
}

+ 0
- 46
src/assets/styles/components/_error-page.scss Прегледај датотеку

@@ -1,46 +0,0 @@
.c-error-page {
margin-top: pxToRem(120px);

@include media-below($bp-md) {
margin-top: pxToRemMd(120px);

.c-error-page__title {
font-size: pxToRemMd(160px);
margin-bottom: pxToRemMd(27px);
}

.c-error-page__text {
margin-bottom: pxToRem(24px);
}
}
}

.c-error-page__content-container {
@include flex-center;
}

.c-error-page__content {
@include flex-column;
align-items: center;
padding: 0 pxToRem(32px);
}

.c-error-page__title {
font-size: pxToRem(160px);
line-height: 1.35;
color: $dark-blue;
margin-bottom: pxToRem(32px);
color: $color-primary;
font-weight: bold;
}

.c-error-page__text {
font-weight: 600;
margin-bottom: pxToRem(24px);
text-align: center;
}

.c-error-page__button {
margin-bottom: pxToRem(16px);
min-width: pxToRem(250px);
}

+ 0
- 23
src/assets/styles/components/_forgot-password.scss Прегледај датотеку

@@ -1,23 +0,0 @@
.c-reset-security {
padding-top: pxToRem(56px);

@include media-below($bp-md) {
padding-top: pxToRemMd(40px);

.c-reset-security__button {
width: 100%;
margin-top: pxToRemMd(44px);
}
}
}

.c-reset-security__question {
color: $dark-blue;
font-weight: 600;
margin-bottom: pxToRem(20px);
}

.c-reset-security__button {
width: 100%;
margin-top: pxToRem(48px);
}

+ 0
- 7
src/assets/styles/components/_icon-button.scss Прегледај датотеку

@@ -1,7 +0,0 @@
.c-icon-button {
@include flex-center;
@include outline-none;
@include button-clear;
user-select: none;
cursor: pointer;
}

+ 0
- 479
src/assets/styles/components/_input.scss Прегледај датотеку

@@ -1,479 +0,0 @@
.c-input {
@include flex-column;
position: relative;

&.c-input--error {
.c-input__field,
.c-select__control,
.c-select__control:hover {
border-color: $red;
}
}

&.c-input--password {
.c-input__icon {
position: absolute;
right: 0;
top: 50%;
transform: translate(0, -50%);
margin-right: pxToRem(12px);
width: pxToRem(24px);
height: pxToRem(24px);
display: flex;

svg {
width: pxToRem(24px);
height: pxToRem(24px);
color: $black;
}
}

.c-input__caps-lock {
position: absolute;
right: 0;
top: 50%;
transform: translate(0, -50%);
margin-right: pxToRem(40px);
width: pxToRem(24px);
height: pxToRem(24px);
display: flex;
width: pxToRem(24px);
height: pxToRem(24px);
color: $black;
}

.c-input__field {
padding-right: pxToRem(72px);
}
}

&.c-input--demi-bold {
.c-input__field {
font-weight: 600;
}
}

&.c-input--search {
position: relative;
width: 100%;

.c-input__icon {
width: pxToRem(24px);
height: pxToRem(24px);
position: absolute;
right: 0;
top: 50%;
transform: translate(0, -50%);
color: $blue-1;
margin-right: pxToRem(12px);
}

&.c-input--search-management {
max-width: pxToRem(344px);
margin-right: pxToRem(24px);

.c-input__field {
height: pxToRem(34px);
font-size: pxToRem(16px);
line-height: 1.5;
letter-spacing: 0;
}
}
}

&.c-input--center-text {
input {
text-align: center;
}
}

@include media-below($bp-xl) {
&.c-input--search {
&.c-input--search-management {
max-width: 100%;
margin-right: pxToRemMd(16px);

.c-input__field {
height: pxToRemMd(32px);
font-size: pxToRemMd(16px);
line-height: 1.5;
letter-spacing: 0;
}
}
}

.c-input__label {
font-size: pxToRemMd(16px);
}

.c-input__field {
font-size: pxToRemMd(16px);
}

.c-input__error {
font-size: pxToRemMd(14px);
}

.c-select__control {
&.c-select__control {
font-size: pxToRemMd(16px);
min-height: 0;

.c-select__input,
.c-select__placeholder {
font-size: pxToRemMd(16px);
}

.c-select__indicator {
> svg {
width: pxToRemMd(16px);
height: pxToRemMd(16px);
}
}
}
}

.c-select__menu {
.c-select__option,
.c-select__menu-notice {
font-size: pxToRemMd(16px);
}
}

.c-input__link {
a,
span {
font-size: pxToRemMd(16px);
}
}

//Overide
.c-password-strength__container {
font-size: pxToRemMd(16px);
}

.c-phone-number {
.PhoneInput {
font-size: pxToRemMd(16px);

&::placeholder {
font-size: pxToRemMd(16px);
}
}

.PhoneInputInput {
font-size: pxToRemMd(16px);
}
}
}

&.c-input--dropdown-full-height {
.c-select__menu {
max-height: initial;
}
}
}

.c-input__label {
color: $blue;
font-size: pxToRem(16px);
font-weight: 600;
letter-spacing: 0;
line-height: 1.75;
margin-bottom: pxToRem(4px);
}

.c-input__field-wrap {
width: 100%;
position: relative;
}

.c-input__field {
@include outline-none;
border: 1px solid $grey-6;
border-radius: $border-radius;
font-size: pxToRem(16px);
line-height: 1.75;
height: pxToRem(50px);
padding: 0 pxToRem(12px);
color: $blue;
background-color: $white;
width: 100%;

&:disabled {
background-color: $grey-8;
border-color: $grey-6;
}

&:focus {
border-color: $color-primary;
}
}

.c-input__error {
position: absolute;
top: 100%;
left: 0;
right: 0;
color: $red;
font-size: pxToRem(14px);
line-height: 1.35;
font-weight: 500;
margin: pxToRem(4px) 0;
}

.c-select__control {
&.c-select__control {
@include outline-none;
border: 1px solid $grey-6;
border-radius: $border-radius;
font-size: pxToRem(16px);
line-height: 1.75;
height: pxToRem(50px);
padding: 0 pxToRem(12px);
color: $blue;
background-color: $white;
box-shadow: none;

&:hover {
border-color: $grey-6;
}

&.c-select__control--is-focused {
border-color: $color-primary;
box-shadow: none;

&:hover {
border-color: $color-primary;
}
&.c-select__control--menu-is-open{
.c-select__indicator {
svg {
transform: rotate(-180deg);
}
}
}
}

.css-1uccc91-singleValue {
color: $blue;
margin: 0;
}

.css-b8ldur-Input {
margin: 0;
}

.c-select__value-container {
height: 100%;
padding: 0;
padding-right: pxToRem(32px);
}

.c-select__input,
.c-select__placeholder {
font-size: pxToRem(16px);
line-height: 1.75;
letter-spacing: 0;
color: $blue;
}

.c-select__indicator-separator {
display: none;
}

.c-select__indicator {
padding: 0;

> svg {
width: pxToRem(16px);
height: pxToRem(16px);
color: $blue;
transform: rotate(0);
transition: transform 0.2s;
}
}

&.c-select__control--is-disabled {
background-color: $grey-8;
}
}
}

.c-select__menu {
@include flex-column;
position: absolute;
top: 100%;
left: 0;
right: 0;
margin-top: pxToRem(4px);
margin-bottom: pxToRem(4px);
border: 1px solid $grey-6;
border-radius: $border-radius;
box-shadow: $box-shadow;
max-height: pxToRem(150px);
overflow: auto;

.c-select__menu-list {
@include flex-column;
padding: 0;
flex-grow: 1;
}

.c-select__option,
.c-select__menu-notice {
padding: pxToRem(12px) pxToRem(15px);
font-size: pxToRem(16px);
line-height: 1.75;
letter-spacing: 0;
color: $blue;
text-align: left;

&:hover {
background-color: $grey-2;
}

&.c-select__option--is-selected {
background-color: $grey-2;
}

&.c-select__option--is-focused {
background-color: $grey-2;
}
}
}

.c-input__link {
position: absolute;
top: 0;
right: 0;

a,
span {
color: $grey-11;
font-size: pxToRem(16px);
letter-spacing: 0;
line-height: 1.15;
text-decoration: underline;
cursor: pointer;
}
}

//Overide
.c-password-strength__container {
margin-top: pxToRem(8px);
font-size: pxToRem(16px);

& .c-password-strength__line--wrapper {
border-radius: 8px;
overflow: hidden;
background-color: $grey;
height: pxToRem(5px);

.c-password-strength__line {
height: pxToRem(5px);
left: 0;
top: 0;
}
}
}

.c-password {
min-height: pxToRem(110px);

@include media-below($bp-xl) {
min-height: pxToRemMd(110px);
}
}

.c-phone-number {
.PhoneInput {
@include outline-none;
box-sizing: border-box;
border: 1px solid $grey-6;
border-radius: $border-radius;
font-size: pxToRem(16px);
line-height: 1.75;
min-height: pxToRem(50px);
color: $blue;
background-color: $white;
box-shadow: none;
width: 100%;
overflow: hidden;

&::placeholder {
font-size: pxToRem(16px);
line-height: 1.75;
}

&:disabled {
background-color: $grey-8;
border-color: $grey-6;
}

&.PhoneInput--focus {
border-color: $color-primary;

.PhoneInputCountry {
border-color: $color-primary;
}
}
}

.PhoneInputCountry {
@include flex-center;
width: pxToRem(96px);
border-right: 1px solid $grey-6;
}

.PhoneInputCountryIcon {
margin-right: pxToRem(16px);
width: auto;
height: auto;
border: none;
}

.PhoneInputCountryIconImg {
width: pxToRem(36px);
object-fit: contain;
}

.PhoneInputCountrySelectArrow {
border: none;
width: 0;
height: 0;
transform: translate(0);
border-left: pxToRem(8px) solid transparent;
border-right: pxToRem(8px) solid transparent;
border-top: pxToRem(8px) solid $blue;
}

.PhoneInputInput {
@include outline-none;
border-color: transparent;
height: 100%;
font-size: pxToRem(16px);
line-height: 1.75;
padding: 0;
color: $blue;
background-color: $white;
width: 100%;
margin: 0;
padding: 0 pxToRem(26px);
height: pxToRem(50px);
}

.PhoneInputCountry {
margin-right: 0;
}

&.c-input--error {
.PhoneInput {
border-color: $red;

.PhoneInputCountry {
border-color: $red;
}
}
}
}

+ 0
- 72
src/assets/styles/components/_loader.scss Прегледај датотеку

@@ -1,72 +0,0 @@
.c-loader__wrapper {
@include flex-column;
flex: 1 1 auto;
position: relative;
min-height: 0;
min-width: 0;

&.c-loader__wrapper--block {
box-shadow: $box-shadow;

.c-loader {
position: relative;
top: unset;
left: unset;
right: unset;
bottom: unset;
}
}

&.c-loader__wrapper--full-height {
height: 100%;
}

&.c-loader__wrapper--no-shadow {
box-shadow: none;
}

.c-loader {
@include flex-center;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
padding: pxToRem(15px) 0;
background-color: rgba(255, 255, 255, 0.4);
z-index: $index-lg;

&.c-loader--page {
position: fixed;

.c-loader__icon {
border: 20px solid transparent;
width: pxToRem(200px);
height: pxToRem(200px);
border-bottom-color: $color-primary;
border-top-color: $color-primary;
}
}
}

.c-loader__icon {
border-radius: 50%;
border: 10px solid transparent;
border-bottom-color: $color-primary;
border-top-color: $color-primary;
animation: 1s loader-animation linear infinite;
width: pxToRem(100px);
height: pxToRem(100px);
}

@keyframes loader-animation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
}

+ 0
- 31
src/assets/styles/components/_login-card.scss Прегледај датотеку

@@ -1,31 +0,0 @@
.c-login-card {
border: 1px solid $color-primary-light;
border-radius: $border-radius;
box-shadow: $box-shadow;
max-width: pxToRem(624px);
width: 100%;
margin: pxToRem(28px) auto 0;
padding: pxToRem(36px) pxToRem(40px) pxToRem(32px);
}

.c-login-card__note {
color: $color-primary;
font-weight: 600;
margin-bottom: pxToRem(37px);
}

.c-login-card__form {
display: grid;
grid-row-gap: pxToRem(24px);
}

.c-login-card__submit {
margin-top: pxToRem(24px);
width: 100%;
}

.c-login-card__question {
color: $blue;
font-weight: 600;
margin-bottom: pxToRem(16px);
}

+ 0
- 72
src/assets/styles/components/_login.scss Прегледај датотеку

@@ -1,72 +0,0 @@
.c-login {
&.c-login--user {
.c-login__form {
.c-input:first-child {
margin-bottom: pxToRem(20px);
}
}
}

@include media-below($bp-xl) {
.c-login__link {
margin-top: pxToRemMd(70px);
}
}

@include media-below($bp-md) {
.c-login__form {
margin: pxToRemMd(36px) 0 0;
}

.c-login__button {
margin-bottom: pxToRemMd(40px);
margin-top: pxToRemMd(36px);
}

.c-login__link {
margin-top: pxToRemMd(80px);
}

&.c-login--user {
.c-login__form {
.c-input:first-child {
margin-bottom: pxToRemMd(20px);
}
}
}
}
}

.c-login__link {
color: $color-primary;
font-weight: 600;
margin-top: pxToRem(40px);
width: max-content;
}

.c-login__form {
margin: pxToRem(36px) 0 0;
> form {
@include flex-column;
}
}

.c-login__button {
width: 100%;
margin-top: pxToRem(68px);
margin-bottom: pxToRem(24px);
}

.c-login__text {
text-align: center;
width: 100%;
color: $blue;

a {
color: $color-primary;
font-weight: bold;
letter-spacing: inherit;
font-size: inherit;
line-height: inherit;
}
}

+ 0
- 169
src/assets/styles/components/_modal.scss Прегледај датотеку

@@ -1,169 +0,0 @@
$header-height-desktop: pxToRem(80px);
$header-height-mobile: pxToRemMd(74px);

.c-modal-wrap {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: $index-xl;
background-color: $black-1;

&.c-modal-wrap--no-bg {
background-color: transparent;
}

&.c-modal-wrap--over-modal {
background-color: transparent;
z-index: $index-xxl;
}

&.c-modal-wrap--sm {
.c-modal {
max-width: pxToRem(390px);
width: 100%;
}

.c-modal__header {
padding: pxToRem(12px);
}
}

.c-modal__header {
padding: pxToRem(12px);
}

&.c-modal-wrap--md {
.c-modal {
max-width: pxToRem(521px);
width: 100%;
}

.c-modal__header {
padding: pxToRem(12px) pxToRem(20px);
}
}

&.c-modal-wrap--lg {
.c-modal {
max-width: pxToRem(782px);
width: 100%;
}

.c-modal__header {
padding: pxToRem(12px) pxToRem(20px);
}
}

&.c-modal-wrap--close {
display: none;
}

@include media-below($bp-xl) {
&,
&.c-modal-wrap--sm,
&.c-modal-wrap--md {
.c-modal {
margin: $header-height-mobile auto $header-height-mobile;
max-height: calc(100vh - #{2 * $header-height-mobile});
}
}
}

@include media-below($bp-md) {
&,
&.c-modal-wrap--sm,
&.c-modal-wrap--md {
.c-modal__header {
padding: pxToRemMd(16px);
}

.c-modal__title {
font-size: pxToRemMd(16px);
line-height: 1.4;
}

.c-modal__close {
width: pxToRemMd(24px);
height: pxToRemMd(24px);
}

.c-modal__back {
width: pxToRemMd(24px);
height: pxToRemMd(24px);
margin-right: pxToRemMd(8px);
}

.c-modal__back-button {
margin-left: -#{pxToRemMd(8px)};
}

.c-modal,
&.c-modal-wrap--lg .c-modal {
max-width: 100%;
max-height: 100vh;
height: 100%;
margin: 0;
border-radius: 0;
}

&.c-modal-wrap--mobile-modal {
display: flex;
padding: 0 pxToRemMd(20px);

.c-modal {
height: auto;
margin: auto;
border-radius: 2px;
}
}
}
}
}

.c-modal {
@include flex-column;
box-shadow: $box-shadow;
border-radius: $border-radius;
background-color: $white;
margin: $header-height-desktop auto $header-height-desktop;
max-height: calc(100vh - #{2 * $header-height-desktop});
position: relative;
}

.c-modal__header {
display: flex;
align-items: center;
box-shadow: $box-shadow;
z-index: $index-xxs;
}

.c-modal__title {
@include text-ellipsis;
font-size: pxToRem(16px);
font-weight: 600;
line-height: 1.5;
color: $dark-blue;
padding-right: pxToRem(10px);
margin-right: auto;
}

.c-modal__close {
width: pxToRem(16px);
height: pxToRem(16px);
color: $dark-blue;
}

.c-modal__back {
width: pxToRem(16px);
height: pxToRem(16px);
color: $dark-blue;
margin-right: pxToRem(10px);
}

.c-modal__body {
@include flex-column;
flex: 1 1 auto;
overflow: auto;
}

+ 0
- 29
src/assets/styles/components/_radio.scss Прегледај датотеку

@@ -1,29 +0,0 @@
.c-radio {
display: flex;
cursor: pointer;

&.c-radio--selected {
border-color: $dark-blue;
}
}

.c-radio__field {
display: none;
}

.c-radio__indicator {
margin-top: pxToRem(4px);
margin-right: pxToRem(16px);
}

.c-radio__icon {
width: pxToRem(16px);
height: pxToRem(16px);
}

.c-radio__text {
font-size: pxToRem(14px);
line-height: 1.15;
color: $blue;
user-select: none;
}

+ 1
- 2
src/components/About/CheckOffersButton/CheckOffersButton.js Прегледај датотеку

@@ -3,12 +3,11 @@ import PropTypes from "prop-types";
import { CheckOffersButtonContainer } from "./CheckOffersButton.styled";
import selectedTheme from "../../../themes";
import { useTranslation } from "react-i18next";
import { useHistory } from "react-router-dom";
import { HOME_PAGE } from "../../../constants/pages";
import history from "../../../store/utils/history";

const CheckOffersButton = () => {
const { t } = useTranslation();
const history = useHistory();
const handleClick = () => {
history.push(HOME_PAGE);
};

+ 4
- 1
src/components/Buttons/ArrowButton/ArrowButton.styled.js Прегледај датотеку

@@ -1,7 +1,7 @@
import IconButton from "../../IconButton/IconButton";
import { ReactComponent as DownArrow } from "../../../assets/images/svg/arrow-down.svg";
import styled from "styled-components";
import selectedTheme from "../../../themes";
import { IconButton } from "../IconButton/IconButton";

export const ArrowIcon = styled(DownArrow)`
${(props) =>
@@ -11,6 +11,9 @@ export const ArrowIcon = styled(DownArrow)`
`}
width: 18px;
height: 18px;
position: relative;
top: 1px;
left: 1px;
& path {
${(props) =>
props.disabled &&

+ 25
- 63
src/components/Cards/ChatCard/ChatCard.js Прегледај датотеку

@@ -3,92 +3,54 @@ import PropTypes from "prop-types";
import {
ChatInfo,
ChatCardContainer,
Col,
UserImage,
UserImgWrapper,
UserName,
LastMessage,
Line,
} from "./ChatCard.styled";
import { useHistory } from "react-router-dom";
import LittleOfferDetails from "./LittleOfferDetails/LittleOfferDetails";
import MobileOfferDetails from "./MobileOfferDetails/MobileOfferDetails";
import OfferLocation from "./OfferLocation/OfferLocation";
import ChatCommands from "./ChatCommands/ChatCommands";
import useIsMobile from "../../../hooks/useIsMobile";
import { getImageUrl, variants } from "../../../util/helpers/imageUrlGetter";
import history from "../../../store/utils/history";
import { replaceInRoute } from "../../../util/helpers/routeHelpers";
import { CHAT_MESSAGE_PAGE } from "../../../constants/pages";

// Chat card is shown only on mobile phones (route /messages)
const ChatCard = (props) => {
const history = useHistory();
const { isMobile } = useIsMobile();

const chat = useMemo(() => {
return props.chat;
}, [props.chat]);

const lastMessage = useMemo(() => {
if (chat?.chat?.messages && chat?.chat?.messages?.length > 0) {
return chat.chat.messages[chat.chat.messages.length - 1]?.text;
}
return "";
}, [chat]);
const routeToItem = () => {
history.push(`/messages/${chat?.chat?._id}`);
history.push(
replaceInRoute(CHAT_MESSAGE_PAGE, {
idChat: chat?.chat?._id,
})
);
};
return (
<ChatCardContainer
onClick={isMobile ? () => routeToItem(chat?.chat?._id) : () => {}}
>
<Col>
<UserImgWrapper>
{/* <UserImage src={chat?.interlocutorData?.image} /> */}
<UserImage
src={getImageUrl(
chat?.interlocutorData?.image,
variants.chatCard,
isMobile
)}
/>
</UserImgWrapper>

<ChatInfo>
<UserName>{chat?.interlocutorData?.name}</UserName>

{/* Only shows on Mobile */}
<MobileOfferDetails chat={chat} />
{/* ^^^^^ */}

<LastMessage>{lastMessage}</LastMessage>
<OfferLocation chat={chat} />
</ChatInfo>
</Col>
<Line />

{/* Only shows on Desktop */}
<LittleOfferDetails chat={chat} />
{/* ^^^^^^^ */}

<ChatCommands routeToItem={() => routeToItem(chat?.chat?._id)} />
return (
<ChatCardContainer onClick={routeToItem}>
<UserImgWrapper>
<UserImage
src={getImageUrl(
chat?.interlocutorData?.image,
variants.chatCard,
isMobile
)}
/>
</UserImgWrapper>

<ChatInfo>
<UserName>{chat?.interlocutorData?.name}</UserName>
<MobileOfferDetails chat={chat} />
</ChatInfo>
</ChatCardContainer>
);
};

ChatCard.propTypes = {
children: PropTypes.node,
title: PropTypes.string,
description: PropTypes.string,
category: PropTypes.string,
author: PropTypes.string,
location: PropTypes.string,
image: PropTypes.node,
quantity: PropTypes.number,
package: PropTypes.string,
numberOfViews: PropTypes.number,
halfwidth: PropTypes.bool,
sponsored: PropTypes.bool,
offer: PropTypes.any,
pinned: PropTypes.bool,
vertical: PropTypes.bool,
chat: PropTypes.any,
};
ChatCard.defaultProps = {

+ 1
- 36
src/components/Cards/ChatCard/ChatCard.styled.js Прегледај датотеку

@@ -18,7 +18,7 @@ export const ChatCardContainer = styled(Container)`
max-width: 2000px;
height: 180px;
position: relative;
justify-content: space-between;
gap: 18px;
@media (max-width: 550px) {
max-height: 108px;
margin: 0;
@@ -55,16 +55,6 @@ export const ChatInfo = styled(Box)`
flex-direction: column;
justify-content: space-between;
`;
export const Col = styled(Box)`
display: flex;
align-items: center;
flex-direction: row;
gap: 18px;
flex: 1;
@media (max-width: 600px) {
${props => props.mobileDisappear && 'display: none;'}
}
`;
export const UserName = styled(Typography)`
margin-bottom: 12px;
font-family: ${selectedTheme.fonts.textFont};
@@ -76,28 +66,3 @@ export const UserName = styled(Typography)`
font-size: 18px;
}
`;
export const LastMessage = styled(Typography)`
font-family: ${selectedTheme.fonts.textFont};
color: ${selectedTheme.colors.primaryDarkTextThird};
line-height: 22px;
font-size: 16px;
max-width: 220px;
flex: 1;
overflow: hidden;
max-height: 66px;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
position: relative;
@media (max-width: 600px) {
display: none;
}
`;
export const Line = styled(Box)`
border-left: 1px solid rgba(0, 0, 0, 0.15);
height: 100px;
width: 0;
margin: auto 0;
@media (max-width: 600px) {
display: none;
}`;

+ 1
- 0
src/components/Cards/ChatCard/ChatCommands/ChatCommands.js Прегледај датотеку

@@ -11,6 +11,7 @@ import selectedTheme from "../../../../themes";
import { useTranslation } from "react-i18next";
import PhonePopover from "../../../Popovers/PhonePopover/PhonePopover";

// Not being used, but kept for potential future needs
const ChatCommands = (props) => {
const { t } = useTranslation();
const [showPhonePopover, setShowPhonePopover] = useState(false);

+ 1
- 1
src/components/Cards/ChatCard/ChatCommands/ChatCommands.styled.js Прегледај датотеку

@@ -2,8 +2,8 @@ import { Box } from "@mui/material";
import styled from "styled-components";
import { ReactComponent as Phone } from "../../../../assets/images/svg/phone.svg";
import selectedTheme from "../../../../themes";
import { IconButton } from "../../../Buttons/IconButton/IconButton";
import { PrimaryButton } from "../../../Buttons/PrimaryButton/PrimaryButton";
import IconButton from "../../../IconButton/IconButton";
import PopoverComponent from "../../../Popovers/PopoverComponent";



+ 1
- 1
src/components/Cards/ChatCard/LittleOfferDetails/LittleOfferDetails.js Прегледај датотеку

@@ -13,6 +13,7 @@ import { Col } from "../ChatCard.styled";
import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter";
import useIsMobile from "../../../../hooks/useIsMobile";

// Not being used, but kept for potential future needs
const LittleOfferDetails = (props) => {
const { t } = useTranslation();
const { isMobile } = useIsMobile();
@@ -21,7 +22,6 @@ const LittleOfferDetails = (props) => {
<Col mobileDisappear>
<ChatOffer>
<OfferImgWrapper>
{/* <OfferImage src={chat?.offerData?.firstImage} /> */}
<OfferImage
src={getImageUrl(
chat?.offerData?.firstImage,

+ 1
- 2
src/components/Cards/ChatCard/MobileOfferDetails/MobileOfferDetails.js Прегледај датотеку

@@ -8,12 +8,11 @@ import {
} from "./MobileOfferDetails.styled";

const MobileOfferDetails = (props) => {
const chat = props.chat;
const { t } = useTranslation();
return (
<OfferCardContainerMobile>
<OfferTextMobile>{t("messages.cardProduct")}</OfferTextMobile>
<OfferTitleMobile>{chat?.offerData?.name}</OfferTitleMobile>
<OfferTitleMobile>{props.chat?.offerData?.name}</OfferTitleMobile>
</OfferCardContainerMobile>
);
};

+ 1
- 0
src/components/Cards/ChatCard/OfferLocation/OfferLocation.js Прегледај датотеку

@@ -7,6 +7,7 @@ import {
XSText,
} from "./OfferLocation.styled";

// Not being used, but kept for potential future needs
const OfferLocation = (props) => {
const chat = props.chat;
return (

+ 1
- 1
src/components/Cards/CreateOfferCard/BackButton/BackButton.js Прегледај датотеку

@@ -17,7 +17,7 @@ const BackButton = (props) => {

BackButton.propTypes = {
setCurrentStep: PropTypes.func,
currentStep: PropTypes.bool,
currentStep: PropTypes.number,
};

export default BackButton;

+ 49
- 73
src/components/Cards/CreateOfferCard/CreateOffer.js Прегледај датотеку

@@ -24,104 +24,74 @@ import BackdropComponent from "../../MUI/BackdropComponent";
import CloseButton from "./CloseButton/CloseButton";
import BackButton from "./BackButton/BackButton";
import selectedTheme from "../../../themes";
import { useMemo } from "react";
import { useLocation } from "react-router-dom";
import { BASE_PAGE, HOME_PAGE } from "../../../constants/pages";
import { routeMatches } from "../../../util/helpers/routeHelpers";

const CreateOffer = ({ closeCreateOfferModal, editOffer, offer }) => {
const dispatch = useDispatch();
const location = useLocation();
const [informations, setInformations] = useState({});
const [currentStep, setCurrentStep] = useState(1);
const { t } = useTranslation();
const userId = useSelector(selectUserId);

const handleApiResponseSuccess = () => {
if (editOffer) {
dispatch(fetchOneOffer(offer._id));
dispatch(fetchProfileOffers(userId));
} else {
if (routeMatches(BASE_PAGE) || routeMatches(HOME_PAGE))
dispatch(fetchOffers({ queryString: "" }));
if (location.pathname.includes("profile"))
dispatch(fetchProfileOffers(userId));
if (location.pathname.includes("proizvodi"))
dispatch(fetchOneOffer(offer._id));
}
};

// Go to next step and save typed values
const handleNext = (values) => {
setInformations({ ...informations, ...values });
setCurrentStep((prevState) => prevState + 1);
console.log({ ...informations, ...values });
};

const newImgs =
informations.images &&
informations.images
.filter((img) => img !== undefined)
.map(
(img) => img
// .replace("data:image/jpg;base64,", "")
// .replace("data:image/jpeg;base64,", "")
// .replace("data:image/png;base64,", "")
);

const offerData = {
name: informations.nameOfProduct,
description: informations.description,
location: {
city: informations.location,
},
condition: informations.condition,
category: {
name: informations.category,
},
subcategory: informations.subcategory,
images: newImgs,
};

const submitOffer = (values) => {
dispatch(addOffer({ values, handleApiResponseSuccess }));
};
// Get new images from 2nd step
const newImgs = useMemo(
() =>
informations.images &&
informations.images.filter((img) => img !== undefined),
[informations.images]
);

const submitEditOffer = (id, values) => {
dispatch(editOneOffer(id, values));
};
// Make offer data object with typed values
const offerData = useMemo(
() => ({
name: informations.nameOfProduct,
description: informations.description,
location: {
city: informations.location,
},
condition: informations.condition,
category: {
name: informations.category,
},
subcategory: informations.subcategory,
images: newImgs,
}),
[informations, newImgs]
);

// Create (or edit) offer
const handleSubmitOffer = () => {
if (editOffer === undefined) {
submitOffer({ offerData, handleApiResponseSuccess });
if (editOffer) {
dispatch(editOneOffer(offer._id, offerData));
} else {
const offerId = offer._id;
submitEditOffer({ offerId, offerData, handleApiResponseSuccess });
dispatch(addOffer({ offerData, handleApiResponseSuccess }));
}
closeCreateOfferModal(false);
};

const goStepBack = (stepNumber) => {
setCurrentStep(stepNumber);
const {
category,
condition,
description,
images,
location,
nameOfProduct,
subcategory,
} = informations;
if (stepNumber === 1) {
setInformations({
category,
condition,
description,
location,
nameOfProduct,
subcategory,
});
}
if (stepNumber === 2) {
setInformations({
category,
condition,
description,
images,
location,
nameOfProduct,
subcategory,
});
}
// Here goes any additional logic
};

return (
@@ -131,8 +101,9 @@ const CreateOffer = ({ closeCreateOfferModal, editOffer, offer }) => {
handleClose={closeCreateOfferModal}
position="fixed"
/>
<ModalCreateOfferContainer currentStep={currentStep}>
<CreateOfferContainer currentStep={currentStep}>
<ModalCreateOfferContainer currentstep={currentStep}>
<CreateOfferContainer currentstep={currentStep}>
{/* Modal header */}
<ModalHeader>
<BackButton
currentStep={currentStep}
@@ -142,13 +113,14 @@ const CreateOffer = ({ closeCreateOfferModal, editOffer, offer }) => {
{currentStep === 3
? `${t("offer.review")}`
: `${
editOffer !== undefined
editOffer
? `${t("offer.changeOffer")}`
: `${t("offer.newOffer")}`
}`}
</CreateOfferTitle>
<CloseButton closeCreateOfferModal={closeCreateOfferModal} />
</ModalHeader>
{/* ^^^^^^^^ */}

<StepProgress
lineColor={selectedTheme.colors.stepProgressAltColor}
@@ -156,13 +128,16 @@ const CreateOffer = ({ closeCreateOfferModal, editOffer, offer }) => {
numberOfSteps={3}
functions={[() => goStepBack(1), () => goStepBack(2)]}
/>

{currentStep === 1 && (
<FirstPartCreateOffer
handleNext={handleNext}
offer={offer}
editOffer={editOffer}
informations={informations}
/>
)}

{currentStep === 2 && (
<SecondPartCreateOffer
handleNext={handleNext}
@@ -170,6 +145,7 @@ const CreateOffer = ({ closeCreateOfferModal, editOffer, offer }) => {
informations={informations}
/>
)}

{currentStep === 3 && (
<ThirdPartCreateOffer
handleSubmitOffer={handleSubmitOffer}

+ 23
- 3
src/components/Cards/CreateOfferCard/CreateOffer.styled.js Прегледај датотеку

@@ -1,16 +1,17 @@
import { Box, Container, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../themes";
import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton";
import { Label } from "../../CheckBox/Label";
import Select from "../../Select/Select";

export const ModalCreateOfferContainer = styled(Box)`
background-color: #fff;
position: fixed;
${(props) => props.currentStep === 3 && `overflow-y: auto;`}
${(props) => props.currentstep === 3 && `overflow-y: auto;`}
max-height: 90vh;
top: ${(props) =>
props.currentStep === 1 ? "calc(50% - 400px);" : "calc(50% - 350px);"};
props.currentstep === 1 ? "calc(50% - 400px);" : "calc(50% - 350px);"};
left: ${(props) =>
props.currentStep !== 3 ? "calc(50% - 310px);" : "calc(50% - 405px);"};
z-index: 150;
@@ -32,7 +33,7 @@ export const ModalCreateOfferContainer = styled(Box)`

@media (max-height: 820px) {
top: ${(props) =>
props.currentStep === 1 ? "calc(50% - 340px)" : "calc(50% - 340px)"};
props.currentstep === 1 ? "calc(50% - 340px)" : "calc(50% - 340px)"};
}

@media (max-width: 810px) {
@@ -204,3 +205,22 @@ export const SelectAltText = styled(Typography)`
position: relative;
bottom: -1px;
`;
export const NextButtonContainer = styled(PrimaryButton)`
margin-top: 16px;
width: 100%;

@media (min-width: 601px) {
margin-bottom: 18px;
}

@media screen and (max-width: 600px) {
position: absolute;
bottom: 18px;
height: 44px;
width: calc(100% - 18px);
left: 9px;
& button {
height: 44px;
}
}
`;

+ 50
- 205
src/components/Cards/CreateOfferCard/FirstPart/FirstPartCreateOffer.js Прегледај датотеку

@@ -1,230 +1,74 @@
import React, { useEffect, useState } from "react";
import React, { useState } from "react";
import PropTypes from "prop-types";
import { useFormik } from "formik";
import {
CreateOfferFormContainer,
DescriptionField,
FieldLabel,
NextButton,
SelectOption,
TitleField,
} from "./FirstPartCreateOffer.styled";
import * as Yup from "yup";
import selectedTheme from "../../../../themes";
import { useTranslation } from "react-i18next";
import { SelectField } from "../CreateOffer.styled";
import { CreateOfferFormContainer } from "./FirstPartCreateOffer.styled";
import { useSelector } from "react-redux";
import useIsMobile from "../../../../hooks/useIsMobile";
import { useMemo } from "react";
import OfferTitleField from "./OfferTitleField/OfferTitleField";
import OfferDescriptionField from "./OfferDescriptionField/OfferDescriptionField";
import OfferLocationField from "./OfferLocationField/OfferLocationField";
import OfferCategoryField from "./OfferCategoryField/OfferCategoryField";
import OfferSubcategoryField from "./OfferSubcategoryField/OfferSubcategoryField";
import NextButton from "./NextButton/NextButton";
import firstPartCreateOfferInitialValues from "../../../../initialValues/createOfferInitialValues/firstPartCreateOfferInitialValues";
import firstPartCreateOfferValidation from "../../../../validations/createOfferValidation/firstPartCreateOfferValidation";

const FirstPartCreateOffer = (props) => {
const [subcat, setSubcat] = useState([]);
const [subcategories, setSubcategories] = useState([]);
const locations = useSelector((state) => state.locations.locations);
const categories = useSelector((state) => state.categories.categories);
const { isMobile } = useIsMobile();

const { t } = useTranslation();
// Change subcategory select options on category change
const handleSubcategories = (category) => {
setSubcategories(
categories
.find((cat) => cat.name === category)
?.subcategories?.map((subcategory) => subcategory.name)
);
};

useEffect(() => {
if (!props.offer) {
if (Object.keys(props.informations).length !== 0) {
formik.setFieldValue("nameOfProduct", props.informations.nameOfProduct);
formik.setFieldValue("description", props.informations.description);
formik.setFieldValue("location", props.informations.location);
formik.setFieldValue("category", props.informations.category);
formik.setFieldValue("subcategory", props.informations.subcategory);
let scat = categories.filter(
(cat) => cat.name === props.informations.category
);
setSubcat(scat[0].subcategories.map((x) => x.name));
}
} else {
formik.setFieldValue("location", props.offer.location.city);
formik.setFieldValue("category", props.offer.category.name);
formik.setFieldValue("subcategory", props.offer.subcategory);
// Get initial values
const initialValues = useMemo(() => {
const newInitialValues = firstPartCreateOfferInitialValues(
props.offer,
props.informations
);
if (categories) {
handleSubcategories(newInitialValues.category);
}
}, [props.offer, props.informations]);
return newInitialValues;
}, [props.offer, props.informations, categories]);

useEffect(() => {
if (props.offer !== undefined) {
let scat = categories.filter(
(cat) => cat.name === props.offer.category.name
);
setSubcat(scat[0].subcategories.map((x) => x.name));
}
}, [props.offer]);
// Get validation schema
const validationSchema = useMemo(() => {
return firstPartCreateOfferValidation(locations, categories, subcategories);
}, [subcategories]);

const handleSubmit = (values) => {
props.handleNext(values);
};

const formik = useFormik({
initialValues: {
nameOfProduct: `${!props.offer ? "" : props.offer.name}`,
description: `${!props.offer ? "" : props.offer.description}`,
location: "default",
category: "default",
subcategory: "default",
},
validationSchema: Yup.object().shape({
nameOfProduct: Yup.string().required(t("login.nameOfProductRequired")),
description: Yup.string().required(t("login.descriptionRequired")).min(8),
location: Yup.string().oneOf(locations.map((l) => l.city)),
category: Yup.string().oneOf(categories.map((c) => c.name)),
// subcategory: Yup.string().oneOf(
// subcat[0]?.subcategories ? subcat[0].subcategories : []
// ),
}),
initialValues,
validationSchema,
onSubmit: handleSubmit,
validateOnBlur: true,
enableReinitialize: true,
});

const handleSubcategories = (category) => {
const filtered = categories.filter((cat) => cat.name === category);
setSubcat(filtered[0].subcategories.map((c) => c.name));
};

return (
<>
<CreateOfferFormContainer component="form" onSubmit={formik.handleSubmit}>
<FieldLabel leftText={t("offer.title")} />
<TitleField
name="nameOfProduct"
placeholder={t("offer.productName")}
italicPlaceholder
margin="normal"
value={formik.values.nameOfProduct}
onChange={formik.handleChange}
error={formik.touched.nameOfProduct && formik.errors.nameOfProduct}
helperText={
formik.touched.nameOfProduct && formik.errors.nameOfProduct
}
autoFocus
fullWidth
/>

<FieldLabel leftText={t("offer.productDescription")} />
{!isMobile ? (
<DescriptionField
name="description"
placeholder={t("offer.description")}
margin="normal"
italicPlaceholder
value={formik.values.description}
onChange={formik.handleChange}
error={formik.touched.description && formik.errors.description}
helperText={formik.touched.description && formik.errors.description}
fullWidth
multiline
minRows={4}
height={"100px"}
/>
) : (
<DescriptionField
name="description"
placeholder={t("offer.description")}
margin="normal"
italicPlaceholder
value={formik.values.description}
onChange={formik.handleChange}
error={formik.touched.description && formik.errors.description}
helperText={formik.touched.description && formik.errors.description}
fullWidth
/>
)}

<FieldLabel leftText={t("offer.location")} />
<SelectField
defaultValue={formik.values.location}
onChange={(value) => {
formik.setFieldValue("location", value.target.value);
}}
value={formik.values.location}
>
<SelectOption style={{ display: "none" }} value="default">
{t("offer.choseLocation")}
</SelectOption>
{locations.map((loc) => {
return (
<SelectOption key={loc._id} value={loc.city}>
{loc.city}
</SelectOption>
);
})}
</SelectField>

<FieldLabel leftText={t("offer.category")} />
<SelectField
defaultValue={formik.values.category}
onChange={(value) => {
formik.setFieldValue("category", value.target.value);
}}
value={formik.values.category}
>
<SelectOption style={{ display: "none" }} value="default">
{t("offer.choseCategory")}
</SelectOption>
{categories.map((cat, i) => {
return (
<SelectOption
key={i}
value={cat.name}
onClick={() => handleSubcategories(cat.name)}
>
{cat.name}
</SelectOption>
);
})}
</SelectField>

<FieldLabel leftText={t("offer.subcategory")} />
<SelectField
defaultValue={formik.values.subcategory}
onChange={(value) => {
formik.setFieldValue("subcategory", value.target.value);
}}
value={formik.values.subcategory}
>
<SelectOption style={{ display: "none" }} value="default">
{t("offer.choseSubcategory")}
</SelectOption>
{subcat &&
subcat.map((sub, i) => {
return (
<SelectOption key={i} value={sub}>
{sub}
</SelectOption>
);
})}
</SelectField>
</CreateOfferFormContainer>

<NextButton
type="submit"
variant="contained"
height="48px"
fullWidth
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor="white"
onClick={formik.handleSubmit}
disabled={
formik.values?.nameOfProduct?.length === 0 ||
!formik.values?.nameOfProduct ||
formik.values?.description?.length === 0 ||
!formik.values?.description ||
formik.values?.category?.length === 0 ||
!formik.values?.category ||
formik.values?.category === "default" ||
formik.values?.subcategory?.length === 0 ||
!formik.values?.subcategory ||
formik.values?.subcategory === "default" ||
formik.values?.location?.length === 0 ||
!formik.values?.location ||
formik.values?.location === "default"
}
>
{t("offer.continue")}
</NextButton>
</>
<CreateOfferFormContainer component="form" onSubmit={formik.handleSubmit}>
<OfferTitleField formik={formik} />
<OfferDescriptionField formik={formik} />
<OfferLocationField formik={formik} locations={locations} />
<OfferCategoryField
formik={formik}
categories={categories}
handleSubcategories={handleSubcategories}
/>
<OfferSubcategoryField formik={formik} subcategories={subcategories} />
<NextButton formik={formik} />
</CreateOfferFormContainer>
);
};

@@ -232,6 +76,7 @@ FirstPartCreateOffer.propTypes = {
children: PropTypes.any,
handleNext: PropTypes.func,
offer: PropTypes.node,
editOffer: PropTypes.bool,
informations: PropTypes.any,
};


+ 0
- 55
src/components/Cards/CreateOfferCard/FirstPart/FirstPartCreateOffer.styled.js Прегледај датотеку

@@ -1,10 +1,8 @@
import { Box, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../../themes";
import { PrimaryButton } from "../../../Buttons/PrimaryButton/PrimaryButton";
import { Label } from "../../../CheckBox/Label";
import Option from "../../../Select/Option/Option";
import { TextField } from "../../../TextFields/TextField/TextField";

export const CreateOfferTitle = styled(Typography)`
font-family: ${selectedTheme.fonts.textFont};
@@ -56,59 +54,6 @@ export const FieldLabel = styled(Label)`
}
}
`;
export const DescriptionField = styled(TextField)`
margin-bottom: 4px;
@media (max-width: 600px) {
margin-bottom: 0;
& div div input {
font-size: 12px !important;
}
& div {
height: 40px;
}
}
`;
export const TitleField = styled(TextField)`
@media (max-width: 600px) {
margin-bottom: 0;
& div div input {
font-size: 12px !important;
}
& div {
height: 40px;
}
}
`;
export const NextButton = styled(PrimaryButton)`
margin-top: 16px;
width: 100%;

@media (min-width: 601px) {
margin-bottom: 18px;
}

@media screen and (max-width: 600px) {
position: absolute;
bottom: 18px;
height: 44px;
/* width: calc(100% - 18px); */
width: 339px;
/* left: 18px; */
& button {
height: 44px;
}
}
@media screen and (max-width: 400px) {
position: absolute;
bottom: 18px;
height: 44px;
width: calc(100% - 18px);
left: 9px;
& button {
height: 44px;
}
}
`;
export const SelectOption = styled(Option)`
height: 40px !important;
min-height: 40px;

+ 44
- 0
src/components/Cards/CreateOfferCard/FirstPart/NextButton/NextButton.js Прегледај датотеку

@@ -0,0 +1,44 @@
import React from "react";
import PropTypes from "prop-types";
import selectedTheme from "../../../../../themes";
import { useTranslation } from "react-i18next";
import { NextButtonContainer } from "../../CreateOffer.styled";

const NextButton = (props) => {
const { t } = useTranslation();
const formik = props.formik;
return (
<NextButtonContainer
type="submit"
variant="contained"
height="48px"
fullWidth
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor="white"
onClick={formik.handleSubmit}
disabled={
formik.values?.nameOfProduct?.length === 0 ||
!formik.values?.nameOfProduct ||
formik.values?.description?.length === 0 ||
!formik.values?.description ||
formik.values?.category?.length === 0 ||
!formik.values?.category ||
formik.values?.category === "default" ||
formik.values?.subcategory?.length === 0 ||
!formik.values?.subcategory ||
formik.values?.subcategory === "default" ||
formik.values?.location?.length === 0 ||
!formik.values?.location ||
formik.values?.location === "default"
}
>
{t("offer.continue")}
</NextButtonContainer>
);
};

NextButton.propTypes = {
formik: PropTypes.any,
};

export default NextButton;

+ 0
- 0
src/components/Cards/CreateOfferCard/FirstPart/NextButton/NextButton.styled.js Прегледај датотеку


+ 45
- 0
src/components/Cards/CreateOfferCard/FirstPart/OfferCategoryField/OfferCategoryField.js Прегледај датотеку

@@ -0,0 +1,45 @@
import React from "react";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
import { FieldLabel, SelectOption } from "../FirstPartCreateOffer.styled";
import { SelectField } from "../../CreateOffer.styled";

const OfferCategoryField = (props) => {
const { t } = useTranslation();
const formik = props.formik;
return (
<>
<FieldLabel leftText={t("offer.category")} />
<SelectField
defaultValue={formik.values.category}
onChange={(value) => {
formik.setFieldValue("category", value.target.value);
}}
value={formik.values.category}
>
<SelectOption style={{ display: "none" }} value="default">
{t("offer.choseCategory")}
</SelectOption>
{props.categories.map((cat, i) => {
return (
<SelectOption
key={i}
value={cat.name}
onClick={() => props.handleSubcategories(cat.name)}
>
{cat.name}
</SelectOption>
);
})}
</SelectField>
</>
);
};

OfferCategoryField.propTypes = {
formik: PropTypes.any,
handleSubcategories: PropTypes.func,
categories: PropTypes.array,
};

export default OfferCategoryField;

+ 0
- 0
src/components/Cards/CreateOfferCard/FirstPart/OfferCategoryField/OfferCategoryField.styled.js Прегледај датотеку


+ 51
- 0
src/components/Cards/CreateOfferCard/FirstPart/OfferDescriptionField/OfferDescriptionField.js Прегледај датотеку

@@ -0,0 +1,51 @@
import React from "react";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
import useIsMobile from "../../../../../hooks/useIsMobile";
import { FieldLabel } from "../FirstPartCreateOffer.styled";
import { DescriptionField } from "./OfferDescriptionField.styled";

const OfferDescriptionField = (props) => {
const formik = props.formik;
const { t } = useTranslation();
const { isMobile } = useIsMobile();
return (
<>
<FieldLabel leftText={t("offer.productDescription")} />
{!isMobile ? (
<DescriptionField
name="description"
placeholder={t("offer.description")}
margin="normal"
italicPlaceholder
value={formik.values.description}
onChange={formik.handleChange}
error={formik.touched.description && formik.errors.description}
helperText={formik.touched.description && formik.errors.description}
fullWidth
multiline
minRows={4}
height={"100px"}
/>
) : (
<DescriptionField
name="description"
placeholder={t("offer.description")}
margin="normal"
italicPlaceholder
value={formik.values.description}
onChange={formik.handleChange}
error={formik.touched.description && formik.errors.description}
helperText={formik.touched.description && formik.errors.description}
fullWidth
/>
)}
</>
);
};

OfferDescriptionField.propTypes = {
formik: PropTypes.any,
};

export default OfferDescriptionField;

+ 15
- 0
src/components/Cards/CreateOfferCard/FirstPart/OfferDescriptionField/OfferDescriptionField.styled.js Прегледај датотеку

@@ -0,0 +1,15 @@
import styled from "styled-components";
import { TextField } from "../../../../TextFields/TextField/TextField";

export const DescriptionField = styled(TextField)`
margin-bottom: 4px;
@media (max-width: 600px) {
margin-bottom: 0;
& div div input {
font-size: 12px !important;
}
& div {
height: 40px;
}
}
`;

+ 40
- 0
src/components/Cards/CreateOfferCard/FirstPart/OfferLocationField/OfferLocationField.js Прегледај датотеку

@@ -0,0 +1,40 @@
import React from "react";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
import { FieldLabel, SelectOption } from "../FirstPartCreateOffer.styled";
import { SelectField } from "../../CreateOffer.styled";

const OfferLocationField = (props) => {
const { t } = useTranslation();
const formik = props.formik;
return (
<>
<FieldLabel leftText={t("offer.location")} />
<SelectField
defaultValue={formik.values.location}
onChange={(value) => {
formik.setFieldValue("location", value.target.value);
}}
value={formik.values.location}
>
<SelectOption style={{ display: "none" }} value="default">
{t("offer.choseLocation")}
</SelectOption>
{props.locations.map((loc) => {
return (
<SelectOption key={loc._id} value={loc.city}>
{loc.city}
</SelectOption>
);
})}
</SelectField>
</>
);
};

OfferLocationField.propTypes = {
formik: PropTypes.any,
locations: PropTypes.array,
};

export default OfferLocationField;

+ 0
- 0
src/components/Cards/CreateOfferCard/FirstPart/OfferLocationField/OfferLocationField.styled.js Прегледај датотеку


+ 41
- 0
src/components/Cards/CreateOfferCard/FirstPart/OfferSubcategoryField/OfferSubcategoryField.js Прегледај датотеку

@@ -0,0 +1,41 @@
import React from "react";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
import { FieldLabel, SelectOption } from "../FirstPartCreateOffer.styled";
import { SelectField } from "../../CreateOffer.styled";

const OfferSubcategoryField = (props) => {
const { t } = useTranslation();
const formik = props.formik;
return (
<>
<FieldLabel leftText={t("offer.subcategory")} />
<SelectField
defaultValue={formik.values.subcategory}
onChange={(value) => {
formik.setFieldValue("subcategory", value.target.value);
}}
value={formik.values.subcategory}
>
<SelectOption style={{ display: "none" }} value="default">
{t("offer.choseSubcategory")}
</SelectOption>
{props.subcategories &&
props.subcategories.map((sub, i) => {
return (
<SelectOption key={i} value={sub}>
{sub}
</SelectOption>
);
})}
</SelectField>
</>
);
};

OfferSubcategoryField.propTypes = {
formik: PropTypes.any,
subcategories: PropTypes.array,
};

export default OfferSubcategoryField;

+ 0
- 0
src/components/Cards/CreateOfferCard/FirstPart/OfferSubcategoryField/OfferSubcategoryField.styled.js Прегледај датотеку


+ 33
- 0
src/components/Cards/CreateOfferCard/FirstPart/OfferTitleField/OfferTitleField.js Прегледај датотеку

@@ -0,0 +1,33 @@
import React from "react";
import PropTypes from "prop-types";
import { FieldLabel } from "../FirstPartCreateOffer.styled";
import { useTranslation } from "react-i18next";
import { TitleField } from "./OfferTitleField.styled";

const OfferTitleField = (props) => {
const { t } = useTranslation();
const formik = props.formik;
return (
<>
<FieldLabel leftText={t("offer.title")} />
<TitleField
name="nameOfProduct"
placeholder={t("offer.productName")}
italicPlaceholder
margin="normal"
value={formik.values.nameOfProduct}
onChange={formik.handleChange}
error={formik.touched.nameOfProduct && formik.errors.nameOfProduct}
helperText={formik.touched.nameOfProduct && formik.errors.nameOfProduct}
autoFocus
fullWidth
/>
</>
);
};

OfferTitleField.propTypes = {
formik: PropTypes.any,
};

export default OfferTitleField;

+ 14
- 0
src/components/Cards/CreateOfferCard/FirstPart/OfferTitleField/OfferTitleField.styled.js Прегледај датотеку

@@ -0,0 +1,14 @@
import styled from "styled-components";
import { TextField } from "../../../../TextFields/TextField/TextField";

export const TitleField = styled(TextField)`
@media (max-width: 600px) {
margin-bottom: 0;
& div div input {
font-size: 12px !important;
}
& div {
height: 40px;
}
}
`;

+ 37
- 0
src/components/Cards/CreateOfferCard/SecondPart/NextButton/NextButton.js Прегледај датотеку

@@ -0,0 +1,37 @@
import React from "react";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
import selectedTheme from "../../../../../themes";
import { NextButtonContainer } from "../../CreateOffer.styled";

const NextButton = (props) => {
const { t } = useTranslation();
const formik = props.formik;
return (
<NextButtonContainer
type="submit"
variant="contained"
height="48px"
fullWidth
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor="white"
onClick={formik.handleSubmit}
disabled={
props.imagesEmpty === props.numberOfImages ||
formik.values?.condition?.length === 0 ||
!formik.values?.condition ||
formik.values?.condition === "default"
}
>
{t("offer.continue")}
</NextButtonContainer>
);
};

NextButton.propTypes = {
formik: PropTypes.any,
imagesEmpty: PropTypes.any,
numberOfImages: PropTypes.any,
};

export default NextButton;

+ 0
- 0
src/components/Cards/CreateOfferCard/SecondPart/NextButton/NextButton.styled.js Прегледај датотеку


+ 47
- 0
src/components/Cards/CreateOfferCard/SecondPart/OfferConditionField/OfferConditionField.js Прегледај датотеку

@@ -0,0 +1,47 @@
import React from "react";
import PropTypes from "prop-types";
import { FieldLabel } from "../SecondPartCreateOffer.styled";
import {
SelectAltText,
SelectField,
SelectText,
} from "../../CreateOffer.styled";
import { SelectOption } from "../../FirstPart/FirstPartCreateOffer.styled";
import { conditionSelectEnum } from "../../../../../enums/conditionEnum";
import { useTranslation } from "react-i18next";
import { InputButtonContainer } from "./OfferConditionField.styled";

const OfferConditionField = (props) => {
const { t } = useTranslation();
const formik = props.formik;
return (
<InputButtonContainer>
<FieldLabel leftText={t("offer.condition")} />
<SelectField
onChange={(event) => {
formik.setFieldValue("condition", event.target.value);
}}
value={formik.values.condition}
>
<SelectOption style={{ display: "none" }} value="default">
{t("offer.choseCondition")}
</SelectOption>
{Object.keys(conditionSelectEnum).map((key) => {
var item = conditionSelectEnum[key];
return (
<SelectOption value={item.mainText} key={item.value}>
<SelectText>{item.mainText}</SelectText>
<SelectAltText>{item.altText}</SelectAltText>
</SelectOption>
);
})}
</SelectField>
</InputButtonContainer>
);
};

OfferConditionField.propTypes = {
formik: PropTypes.any,
};

export default OfferConditionField;

+ 10
- 0
src/components/Cards/CreateOfferCard/SecondPart/OfferConditionField/OfferConditionField.styled.js Прегледај датотеку

@@ -0,0 +1,10 @@
import { Box } from "@mui/material";
import styled from "styled-components";

export const InputButtonContainer = styled(Box)`
width: 332px;
margin: 25px auto;
display: flex;
flex-direction: column;
justify-content: center;
`;

+ 29
- 0
src/components/Cards/CreateOfferCard/SecondPart/OfferImagePicker/OfferImagePicker.js Прегледај датотеку

@@ -0,0 +1,29 @@
import React from "react";
import PropTypes from "prop-types";
import ImagePicker from "../../../../ImagePicker/ImagePicker";
import { Scroller } from "./OfferImagePicker.styled";

const OfferImagePicker = (props) => {
return (
<Scroller>
{props.images.map((item, index) => {
return (
<ImagePicker
key={index}
image={item}
setImage={(image) => props.setImage(index, image)}
deleteImage={() => props.setImage(index, null)}
showDeleteIcon
/>
);
})}
</Scroller>
);
};

OfferImagePicker.propTypes = {
images: PropTypes.array,
setImage: PropTypes.func,
};

export default OfferImagePicker;

+ 8
- 0
src/components/Cards/CreateOfferCard/SecondPart/OfferImagePicker/OfferImagePicker.styled.js Прегледај датотеку

@@ -0,0 +1,8 @@
import styled from "styled-components";
import HorizontalScroller from "../../../../Scroller/HorizontalScroller";

export const Scroller = styled(HorizontalScroller)`
min-width: 100%;
position: relative;
margin-bottom: 36px;
`;

+ 38
- 114
src/components/Cards/CreateOfferCard/SecondPart/SecondPartCreateOffer.js Прегледај датотеку

@@ -1,23 +1,17 @@
import React, { useMemo, useState, useEffect } from "react";
import React, { useMemo, useState } from "react";
import PropTypes from "prop-types";
import {
CreateOfferFormContainer,
FieldLabel,
Scroller,
SupportedFormats,
InputButtonContainer,
} from "./SecondPartCreateOffer.styled";
import ImagePicker from "../../../ImagePicker/ImagePicker";
import { useTranslation, Trans } from "react-i18next";
import { SelectAltText, SelectField, SelectText } from "../CreateOffer.styled";
import {
NextButton,
SelectOption,
} from "../FirstPart/FirstPartCreateOffer.styled";
import selectedTheme from "../../../../themes";
import { conditionSelectEnum } from "../../../../enums/conditionEnum";
import { Trans } from "react-i18next";
import { useFormik } from "formik";
import * as Yup from "yup";
import { useEffect } from "react";
import OfferImagePicker from "./OfferImagePicker/OfferImagePicker";
import OfferConditionField from "./OfferConditionField/OfferConditionField";
import NextButton from "./NextButton/NextButton";
import secondPartCreateOfferValidation from "../../../../validations/createOfferValidation/secondPartCreateOfferValidation";
import secondPartCreateOfferInitialValues from "../../../../initialValues/createOfferInitialValues/secondPartCreateOfferInitialValues";

const numberOfImages = 3;

@@ -25,41 +19,29 @@ const SecondPartCreateOffer = (props) => {
const [images, setImages] = useState(
Array.apply(null, Array(numberOfImages)).map(() => {})
); // 3 images
const { t } = useTranslation();

useEffect(() => {
if (!props.offer) {
if (Object.keys(props.informations).length > 6) {
setImages(
props.informations?.images
? [...props.informations.images]
: [...images]
);
formik.setFieldValue(
"condition",
props.informations?.condition
? props.informations.condition
: "default"
);
}
} else {
formik.setFieldValue("condition", props.offer.condition);
}
}, [props.offer, props.informations]);
const initialValues = useMemo(() => {
return secondPartCreateOfferInitialValues(
props?.informations,
props?.offer,
images
);
}, [props?.informations, props?.offer, images]);

useEffect(() => {
setImages((prevState) => {
let editedImages = [...prevState];
if (props.offer !== undefined && props.offer.images.length !== 0) {
editedImages[0] = props.offer.images[0];
props.offer.images.forEach((oldImage, index) => {
editedImages[index] = oldImage
})
}
formik.setFieldValue("images", images);
}, [images]);

return [...editedImages];
});
}, [props.offer]);
useEffect(() => {
if (props?.offer?.images || props?.informations?.images) {
const oldImages = props?.informations?.images || props?.offer?.images;
let newImages = [...images];
oldImages.forEach((newImage, index) => {
newImages[index] = newImage;
});
setImages([...newImages]);
}
}, [props?.offer, props?.informations]);

const setImage = (index, image) => {
setImages((prevState) => {
@@ -69,10 +51,11 @@ const SecondPartCreateOffer = (props) => {
});
};

//How many images are empty
const imagesEmpty = useMemo(() => {
let numOfImagesEmpty = 0;
images.forEach((item) => {
if (item === null || item === undefined) numOfImagesEmpty++;
if (!item) numOfImagesEmpty++;
});
return numOfImagesEmpty;
}, [images]);
@@ -81,22 +64,9 @@ const SecondPartCreateOffer = (props) => {
props.handleNext(values);
};

const conditionSelectEnumArray = Object.values(conditionSelectEnum);
const filteredconditionSelectEnumArray = conditionSelectEnumArray.map(
(item) => item.mainText
);

const formik = useFormik({
initialValues: {
images: images,
condition:
props.informations?.condition || props.offer?.condition || "default",
},
validationSchema: Yup.object().shape({
condition: Yup.string()
.required()
.oneOf(filteredconditionSelectEnumArray),
}),
initialValues,
validationSchema: secondPartCreateOfferValidation,
onSubmit: handleSubmit,
validateOnBlur: true,
enableReinitialize: true,
@@ -105,64 +75,18 @@ const SecondPartCreateOffer = (props) => {
return (
<>
<CreateOfferFormContainer component="form" onSubmit={formik.handleSubmit}>
<Scroller>
{images.map((item, index) => {
return (
<ImagePicker
key={index}
image={item}
setImage={(image) => setImage(index, image)}
deleteImage={() => setImage(index, null)}
showDeleteIcon
/>
);
})}
</Scroller>
<OfferImagePicker images={images} setImage={setImage} />
<SupportedFormats>
<Trans i18nKey="offer.supportedImagesFormats" />
</SupportedFormats>
<InputButtonContainer>
<FieldLabel leftText={t("offer.condition")} />
<SelectField
onChange={(value) => {
formik.setFieldValue("condition", value.target.value);
}}
value={formik.values.condition}
>
<SelectOption style={{ display: "none" }} value="default">
{t("offer.choseCondition")}
</SelectOption>
{Object.keys(conditionSelectEnum).map((key) => {
var item = conditionSelectEnum[key];
return (
<SelectOption value={item.mainText} key={item.value}>
<SelectText>{item.mainText}</SelectText>
<SelectAltText>{item.altText}</SelectAltText>
</SelectOption>
);
})}
</SelectField>
</InputButtonContainer>
<OfferConditionField formik={formik} />
</CreateOfferFormContainer>
<NextButton
type="submit"
variant="contained"
height="48px"
fullWidth
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor="white"
onClick={formik.handleSubmit}
disabled={
(props.offer === undefined
? imagesEmpty === numberOfImages
: false) ||
formik.values?.condition?.length === 0 ||
!formik.values?.condition ||
formik.values?.condition === "default"
}
>
{t("offer.continue")}
</NextButton>
formik={formik}
offer={props.offer}
imagesEmpty={imagesEmpty}
numberOfImages={numberOfImages}
/>
</>
);
};

+ 0
- 14
src/components/Cards/CreateOfferCard/SecondPart/SecondPartCreateOffer.styled.js Прегледај датотеку

@@ -2,7 +2,6 @@ import { Box, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../../themes";
import { Label } from "../../../CheckBox/Label";
import HorizontalScroller from "../../../Scroller/HorizontalScroller";

export const CreateOfferFormContainer = styled(Box)`
padding-top: 20px;
@@ -23,19 +22,6 @@ export const FieldLabel = styled(Label)`
}
`;

export const InputButtonContainer = styled(Box)`
width: 332px;
margin: 25px auto;
display: flex;
flex-direction: column;
justify-content: center;
`;

export const Scroller = styled(HorizontalScroller)`
min-width: 100%;
position: relative;
margin-bottom: 36px;
`;

export const SupportedFormats = styled(Typography)`
font-size: 13px;

+ 23
- 17
src/components/Cards/CreateOfferCard/ThirdPart/ThirdPartCreateOffer.js Прегледај датотеку

@@ -1,26 +1,32 @@
import React from "react";
import PropTypes from "prop-types";
import { PreviewCard, PublishButton } from "./ThirdPartCreateOffer.styled";
// import { NextButton } from "../FirstPart/FirstPartCreateOffer.styled";
import { PreviewCard } from "./ThirdPartCreateOffer.styled";
import selectedTheme from "../../../../themes";
import { CreateOfferFormContainer } from "../CreateOffer.styled";
import {
CreateOfferFormContainer,
NextButtonContainer,
} from "../CreateOffer.styled";
import { useTranslation } from "react-i18next";
import { useMemo } from "react";

const ThirdPartCreateOffer = (props) => {
const { t } = useTranslation();
const offer = {
offer: {
category: {
name: props.informations.category,
const offer = useMemo(
() => ({
offer: {
category: {
name: props.informations.category,
},
subcategory: props.informations.subcategory,
condition: props.informations.condition,
_created: new Date().toString(),
images: props.informations.images.filter((item) => item !== undefined),
name: props.informations.nameOfProduct,
description: props.informations.description,
},
subcategory: props.informations.subcategory,
condition: props.informations.condition,
_created: new Date().toString(),
images: props.informations.images.filter((item) => item !== undefined),
name: props.informations.nameOfProduct,
description: props.informations.description,
},
};
}),
[props.informations]
);
const handleSubmit = (e) => {
e.preventDefault();
props.handleSubmitOffer();
@@ -44,7 +50,7 @@ const ThirdPartCreateOffer = (props) => {
previewCard
/>
</CreateOfferFormContainer>
<PublishButton
<NextButtonContainer
type="submit"
variant="contained"
height="48px"
@@ -53,7 +59,7 @@ const ThirdPartCreateOffer = (props) => {
onClick={handleSubmit}
>
{t("offer.publish")}
</PublishButton>
</NextButtonContainer>
</>
);
};

+ 0
- 2
src/components/Cards/FilterCard/FilterCard.js Прегледај датотеку

@@ -27,7 +27,6 @@ const FilterCard = (props) => {
skeleton={props.skeleton}
>
<SkeletonFilterCard
animationStage={props.animationStage}
skeleton={props.skeleton}
/>
{/* Header title for my offers */}
@@ -75,7 +74,6 @@ FilterCard.propTypes = {
closeResponsive: PropTypes.func,
myOffers: PropTypes.bool,
skeleton: PropTypes.bool,
animationStage: PropTypes.number,
filtersOpened: PropTypes.bool,
toggleFilters: PropTypes.func,
};

+ 0
- 68
src/components/Cards/FilterCard/Mockupdata.js Прегледај датотеку

@@ -1,68 +0,0 @@
export default [[{
string: "Beograd",
numberOfProducts: 17,
id: 0,
checked: false
}
,{
string: "Nis",
numberOfProducts: 137,
id: 1,
checked: false
}
,{
string: "Novi Sad",
numberOfProducts: 57,
id: 2,
checked: false
}
,{
string: "Kragujevac",
numberOfProducts: 62,
id: 3,
checked: false
}
,{
string: "Leskovac",
numberOfProducts: 1,
id: 4,
checked: false
}
,{
string: "Vranje",
numberOfProducts: 23,
id: 5,
checked: false
}],
[
{
string: "SVE KATEGORIJE",
numberOfProducts: 259,
id: 0,
},
{
string: "Kategorija 1",
numberOfProducts: 46,
id: 1,
},
{
string: "Kategorija 2",
numberOfProducts: 26,
id: 2,
},
{
string: "Kategorija 3",
numberOfProducts: 91,
id: 3,
},
{
string: "Kategorija 4",
numberOfProducts: 23,
id: 4,
},
{
string: "Kategorija 5",
numberOfProducts: 20,
id: 5,
},
]];

+ 4
- 5
src/components/Cards/FilterCard/Skeleton/SkeletonChooserHeader/SkeletonChooserHeader.js Прегледај датотеку

@@ -8,21 +8,20 @@ import {
SkeletonChooserContainer,
} from "./SkeletonChooserHeader.styled";

const SkeletonChooserHeader = (props) => {
const SkeletonChooserHeader = () => {
return (
<SkeletonChooserContainer>
<LeftContainer>
<CircleOne animationStage={props.animationStage}/>
<Line animationStage={props.animationStage}/>
<CircleOne/>
<Line/>
</LeftContainer>
<CircleSecond animationStage={props.animationStage}/>
<CircleSecond/>
</SkeletonChooserContainer>
);
};

SkeletonChooserHeader.propTypes = {
children: PropTypes.node,
animationStage: PropTypes.any,
};

export default SkeletonChooserHeader;

+ 2
- 3
src/components/Cards/FilterCard/Skeleton/SkeletonChooserTitle/SkeletonChooserTitle.js Прегледај датотеку

@@ -4,8 +4,8 @@ import { SkeletonChooserTitleContainer, SkeletonChooserTitleLine } from './Skele

const SkeletonChooserTitle = (props) => {
return (
<SkeletonChooserTitleContainer center={props.center} animationStage={props.animationStage} >
<SkeletonChooserTitleLine center={props.center} animationStage={props.animationStage}/>
<SkeletonChooserTitleContainer center={props.center} >
<SkeletonChooserTitleLine center={props.center} />
</SkeletonChooserTitleContainer>
)
}
@@ -13,7 +13,6 @@ const SkeletonChooserTitle = (props) => {
SkeletonChooserTitle.propTypes = {
children: PropTypes.any,
center: PropTypes.bool,
animationStage: PropTypes.number,
}

export default SkeletonChooserTitle

+ 11
- 12
src/components/Cards/FilterCard/Skeleton/SkeletonFilterCard.js Прегледај датотеку

@@ -13,26 +13,25 @@ import SkeletonSection from "./SkeletonSection/SkeletonSection";
const SkeletonFilterCard = (props) => {

return (
<SkeletonFilterCardContainer animationStage={props.animationStage} skeleton={props.skeleton}>
<SkeletonFilterCardContainer skeleton={props.skeleton}>
<SkeletonHeader>
<SkeletonHeaderLineOne animationStage={props.animationStage} />
<SkeletonHeaderLineSecond animationStage={props.animationStage} />
<SkeletonHeaderLineOne />
<SkeletonHeaderLineSecond />
</SkeletonHeader>
<SkeletonChooserHeader animationStage={props.animationStage}/>
<SkeletonChooserTitle animationStage={props.animationStage} />
<SkeletonSection numberOfOptions={14} animationStage={props.animationStage} />
<SkeletonChooserHeader animationStage={props.animationStage} />
<SkeletonChooserHeader animationStage={props.animationStage} />
<SkeletonChooserTitle animationStage={props.animationStage} />
<SkeletonSection numberOfOptions={3} animationStage={props.animationStage} />
<SkeletonChooserTitle center animationStage={props.animationStage} />
<SkeletonChooserHeader/>
<SkeletonChooserTitle />
<SkeletonSection numberOfOptions={14} />
<SkeletonChooserHeader />
<SkeletonChooserHeader />
<SkeletonChooserTitle />
<SkeletonSection numberOfOptions={3} />
<SkeletonChooserTitle center />
</SkeletonFilterCardContainer>
);
};

SkeletonFilterCard.propTypes = {
children: PropTypes.any,
animationStage: PropTypes.number,
skeleton: PropTypes.bool,
};


+ 1
- 2
src/components/Cards/FilterCard/Skeleton/SkeletonSection/SkeletonSection.js Прегледај датотеку

@@ -10,7 +10,7 @@ const SkeletonSection = (props) => {
return (
<SkeletonSectionContainer>
{arrayForMapping.map((item, index) => (
<SkeletonSectionOption key={index} animationStage={props.animationStage} />
<SkeletonSectionOption key={index} />
))}
</SkeletonSectionContainer>
);
@@ -19,7 +19,6 @@ const SkeletonSection = (props) => {
SkeletonSection.propTypes = {
children: PropTypes.node,
numberOfOptions: PropTypes.number,
animationStage: PropTypes.number,
};

export default SkeletonSection;

+ 4
- 5
src/components/Cards/FilterCard/Skeleton/SkeletonSection/SkeletonSectionOption/SkeletonSectionOption.js Прегледај датотеку

@@ -2,21 +2,20 @@ import React from 'react'
import PropTypes from 'prop-types'
import { Circle, EndLine, Line, OptionLeftContainer, SkeletonSectionOptionContainer } from './SkeletonSectionOption.styled'

const SkeletonSectionOption = (props) => {
const SkeletonSectionOption = () => {
return (
<SkeletonSectionOptionContainer>
<OptionLeftContainer>
<Circle animationStage={props.animationStage} />
<Line animationStage={props.animationStage} />
<Circle/>
<Line/>
</OptionLeftContainer>
<EndLine animationStage={props.animationStage} />
<EndLine/>
</SkeletonSectionOptionContainer>
)
}

SkeletonSectionOption.propTypes = {
children: PropTypes.any,
animationStage: PropTypes.number,
}

export default SkeletonSectionOption

+ 0
- 1
src/components/Cards/LittleOfferCard/LittleOfferCard.js Прегледај датотеку

@@ -17,7 +17,6 @@ const LittleOfferCard = (props) => {
const { isMobile } = useIsMobile();
return (
<LittleOfferCardContainer>
{/* <OfferImage src={props.image} /> */}
<OfferImage
src={getImageUrl(props.image, variants.reviewCard, isMobile)}
/>

+ 0
- 1
src/components/Cards/MessageCard/MessageCard.js Прегледај датотеку

@@ -18,7 +18,6 @@ const MessageCard = (props) => {
const dateString = formatDateTime(new Date(message._created));
return (
<MessageCardContainer ismymessage={props.isMyMessage}>
{/* <ProfileImage src={props.image} /> */}
<ProfileImage
src={getImageUrl(props.image, variants.chatMessage, isMobile)}
/>

+ 8
- 4
src/components/Cards/MiniChatCard/MiniChatCard.js Прегледај датотеку

@@ -9,20 +9,24 @@ import {
ProfileProductName,
} from "./MiniChatCard.styled";
import { useTranslation } from "react-i18next";
import { useHistory } from "react-router-dom";
import useIsMobile from "../../../hooks/useIsMobile";
import { getImageUrl, variants } from "../../../util/helpers/imageUrlGetter";
import history from "../../../store/utils/history";
import { replaceInRoute } from "../../../util/helpers/routeHelpers";
import { CHAT_MESSAGE_PAGE } from "../../../constants/pages";

const MiniChatCard = (props) => {
const { t } = useTranslation();
const history = useHistory();
const { isMobile } = useIsMobile();
const changeChat = () => {
history.push(`/messages/${props?.chat?.chat?._id}`);
history.push(
replaceInRoute(CHAT_MESSAGE_PAGE, {
idChat: props?.chat?.chat?._id,
})
);
};
return (
<MiniChatCardContainer selected={props.selected} onClick={changeChat}>
{/* <ProfileImage src={props?.chat?.interlocutorData?.image} /> */}
<ProfileImage
src={getImageUrl(
props?.chat?.interlocutorData?.image,

+ 36
- 0
src/components/Cards/OfferCard/CheckButton/CheckButton.js Прегледај датотеку

@@ -0,0 +1,36 @@
import React from "react";
import PropTypes from "prop-types";
import selectedTheme from "../../../../themes";
import { replaceInRoute } from "../../../../util/helpers/routeHelpers";
import { ITEM_DETAILS_PAGE } from "../../../../constants/pages";
import { useTranslation } from "react-i18next";
import { CheckButtonContainer } from "./CheckButton.styled";

const CheckButton = (props) => {
const { t } = useTranslation();
const routeToItem = (itemId) => {
history.push(
replaceInRoute(ITEM_DETAILS_PAGE, {
idProizvod: itemId,
})
);
};
return (
<CheckButtonContainer
variant={props.sponsored ? "contained" : "outlined"}
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor={props.sponsored ? "white" : selectedTheme.colors.primaryPurple}
style={{ fontWeight: "600" }}
onClick={() => routeToItem(props.offerId)}
>
{t("offer.checkButtonLabel")}
</CheckButtonContainer>
);
};

CheckButton.propTypes = {
sponsored: PropTypes.bool,
offerId: PropTypes.string,
};

export default CheckButton;

+ 18
- 0
src/components/Cards/OfferCard/CheckButton/CheckButton.styled.js Прегледај датотеку

@@ -0,0 +1,18 @@
import styled from "styled-components";
import selectedTheme from "../../../../themes";
import { PrimaryButton } from "../../../Buttons/PrimaryButton/PrimaryButton";

export const CheckButtonContainer = styled(PrimaryButton)`
width: 180px;
height: 48px;
position: absolute;
bottom: 9px;
right: 9px;
&:hover button {
background-color: ${selectedTheme.colors.primaryPurple} !important;
color: white !important;
}
@media (max-width: 650px) {
display: none;
}
`;

+ 28
- 0
src/components/Cards/OfferCard/DeleteOffer/CancelButton/CancelButton.js Прегледај датотеку

@@ -0,0 +1,28 @@
import React from "react";
import PropTypes from "prop-types";
import selectedTheme from "../../../../../themes";
import { CancelButtonContainer } from "./CancelButton.styled";
import { useTranslation } from "react-i18next";

const CancelButton = (props) => {
const { t } = useTranslation();
return (
<CancelButtonContainer
variant="contained"
height="48px"
width="180px"
fullWidth
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor="white"
onClick={props.onClick}
>
{t("deleteOffer.cancel")}
</CancelButtonContainer>
);
};

CancelButton.propTypes = {
onClick: PropTypes.func,
};

export default CancelButton;

+ 9
- 0
src/components/Cards/OfferCard/DeleteOffer/CancelButton/CancelButton.styled.js Прегледај датотеку

@@ -0,0 +1,9 @@
import styled from "styled-components";
import { PrimaryButton } from "../../../../Buttons/PrimaryButton/PrimaryButton";

export const CancelButtonContainer = styled(PrimaryButton)`
@media screen and (max-width: 600px) {
width: 140px;
height: 45px;
}
`;

+ 10
- 43
src/components/Cards/OfferCard/DeleteOffer/DeleteOffer.js Прегледај датотеку

@@ -7,17 +7,9 @@ import {
OfferInfo,
OfferImageContainer,
OfferImage,
OfferDescription,
OfferDescriptionTitle,
OfferDescriptionCategory,
CancelButton,
RemoveIconContainer,
RemoveIcon,
SaveButton,
CategoryIcon,
} from "./DeleteOffer.styled";
import selectedTheme from "../../../../themes";
import { ReactComponent as Category } from "../../../../assets/images/svg/category.svg";
import BackdropComponent from "../../../MUI/BackdropComponent";
import { useDispatch, useSelector } from "react-redux";
import {
@@ -25,15 +17,17 @@ import {
fetchProfileOffers,
removeOffer,
} from "../../../../store/actions/offers/offersActions";
import { useTranslation, Trans } from "react-i18next";
import { Trans } from "react-i18next";
import { useHistory } from "react-router-dom";
import useIsMobile from "../../../../hooks/useIsMobile";
import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter";
import { selectQueryString } from "../../../../store/selectors/queryStringSelectors";
import OfferDescription from "./OfferDescription/OfferDescription";
import CancelButton from "./CancelButton/CancelButton";
import SaveButton from "./SaveButton/SaveButton";

const DeleteOffer = (props) => {
const dispatch = useDispatch();
const { t } = useTranslation();
const queryString = useSelector(selectQueryString);
const history = useHistory();
const userId = props.offer.userId;
@@ -66,7 +60,6 @@ const DeleteOffer = (props) => {
<DeleteOfferContainer>
<OfferInfo>
<OfferImageContainer>
{/* <OfferImage src={props.offer.images[0]} /> */}
<OfferImage
src={getImageUrl(
props.offer.images[0],
@@ -75,15 +68,10 @@ const DeleteOffer = (props) => {
)}
/>
</OfferImageContainer>
<OfferDescription>
<OfferDescriptionTitle>{props.offer.name}</OfferDescriptionTitle>
<OfferDescriptionCategory>
<CategoryIcon color="#c4c4c4" component="span" size="16px">
<Category />
</CategoryIcon>
{props.offer.category.name}
</OfferDescriptionCategory>
</OfferDescription>
<OfferDescription
offerName={props.offer.name}
categoryName={props.offer.category.name}
/>
<RemoveIconContainer>
<RemoveIcon />
</RemoveIconContainer>
@@ -92,29 +80,8 @@ const DeleteOffer = (props) => {
<Trans i18nKey="deleteOffer.areYouSure" />
</DeleteQuestion>
<ButtonsContainer>
<CancelButton
variant="contained"
height="48px"
width="180px"
fullWidth
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor="white"
onClick={closeDeleteModalHandler}
>
{t("deleteOffer.cancel")}
</CancelButton>
<SaveButton
type="submit"
variant="outlined"
height="48px"
width="180px"
fullWidth
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor={selectedTheme.colors.primaryPurple}
onClick={removeOfferHandler}
>
{t("deleteOffer.delete")}
</SaveButton>
<CancelButton onClick={closeDeleteModalHandler} />
<SaveButton onClick={removeOfferHandler} />
</ButtonsContainer>
</DeleteOfferContainer>
</>

+ 0
- 46
src/components/Cards/OfferCard/DeleteOffer/DeleteOffer.styled.js Прегледај датотеку

@@ -1,8 +1,6 @@
import { Typography } from "@mui/material";
import { Box } from "@mui/system";
import styled from "styled-components";
import { PrimaryButton } from "../../../Buttons/PrimaryButton/PrimaryButton";
import { Icon } from "../../../Icon/Icon";
import { ReactComponent as Remove } from "../../../../assets/images/svg/trash-gold.svg";
import selectedTheme from "../../../../themes";
import { IconButton } from "../../../Buttons/IconButton/IconButton";
@@ -60,36 +58,6 @@ export const OfferImage = styled.img`
border-radius: 2px;
`;

export const OfferDescription = styled(Box)`
display: flex;
flex-direction: column;
margin-left: 9px;
`;

export const OfferDescriptionTitle = styled(Typography)`
font-size: 16px;
font-weight: 600;
color: ${selectedTheme.colors.primaryPurple};

@media screen and (max-width: 600px) {
font-size: 14px;
}
`;

export const OfferDescriptionCategory = styled(Typography)`
font-size: 12px;
letter-spacing: 2%;
`;

export const CategoryIcon = styled(Icon)`
margin-right: 4px;
& svg {
width: 14px;
position: relative;
top: -1px;
}
`;

export const DeleteQuestion = styled(Typography)`
font-family: ${selectedTheme.fonts.textFont};
font-size: 16px;
@@ -134,17 +102,3 @@ export const ButtonsContainer = styled(Box)`
width: 100%;
justify-content: space-between;
`;

export const CancelButton = styled(PrimaryButton)`
@media screen and (max-width: 600px) {
width: 140px;
height: 45px;
}
`;

export const SaveButton = styled(PrimaryButton)`
@media screen and (max-width: 600px) {
width: 140px;
height: 45px;
}
`;

+ 35
- 0
src/components/Cards/OfferCard/DeleteOffer/OfferDescription/OfferDescription.js Прегледај датотеку

@@ -0,0 +1,35 @@
import React from "react";
import PropTypes from "prop-types";
import {
CategoryIcon,
CategoryIconContainer,
OfferDescriptionCategory,
OfferDescriptionContainer,
OfferDescriptionTitle,
} from "./OfferDescription.styled";
import selectedTheme from "../../../../../themes";

const OfferDescription = (props) => {
return (
<OfferDescriptionContainer>
<OfferDescriptionTitle>{props.offerName}</OfferDescriptionTitle>
<OfferDescriptionCategory>
<CategoryIconContainer
color={selectedTheme.colors.iconStrokeDisabledColor}
component="span"
size="16px"
>
<CategoryIcon />
</CategoryIconContainer>
{props.categoryName}
</OfferDescriptionCategory>
</OfferDescriptionContainer>
);
};

OfferDescription.propTypes = {
offerName: PropTypes.string,
categoryName: PropTypes.string,
};

export default OfferDescription;

+ 37
- 0
src/components/Cards/OfferCard/DeleteOffer/OfferDescription/OfferDescription.styled.js Прегледај датотеку

@@ -0,0 +1,37 @@
import { Box, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../../../themes";
import { Icon } from "../../../../Icon/Icon";
import { ReactComponent as Category } from "../../../../../assets/images/svg/category.svg";

export const OfferDescriptionContainer = styled(Box)`
display: flex;
flex-direction: column;
margin-left: 9px;
`;

export const OfferDescriptionTitle = styled(Typography)`
font-size: 16px;
font-weight: 600;
color: ${selectedTheme.colors.primaryPurple};

@media screen and (max-width: 600px) {
font-size: 14px;
}
`;

export const OfferDescriptionCategory = styled(Typography)`
font-size: 12px;
letter-spacing: 2%;
`;

export const CategoryIconContainer = styled(Icon)`
margin-right: 4px;
& svg {
width: 14px;
position: relative;
top: -1px;
}
`;
export const CategoryIcon = styled(Category)`
`

+ 29
- 0
src/components/Cards/OfferCard/DeleteOffer/SaveButton/SaveButton.js Прегледај датотеку

@@ -0,0 +1,29 @@
import React from "react";
import PropTypes from "prop-types";
import selectedTheme from "../../../../../themes";
import { useTranslation } from "react-i18next";
import { SaveButtonContainer } from "./SaveButton.styled";

const SaveButton = (props) => {
const { t } = useTranslation();
return (
<SaveButtonContainer
type="submit"
variant="outlined"
height="48px"
width="180px"
fullWidth
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor={selectedTheme.colors.primaryPurple}
onClick={props.onClick}
>
{t("deleteOffer.delete")}
</SaveButtonContainer>
);
};

SaveButton.propTypes = {
onClick: PropTypes.func,
};

export default SaveButton;

+ 9
- 0
src/components/Cards/OfferCard/DeleteOffer/SaveButton/SaveButton.styled.js Прегледај датотеку

@@ -0,0 +1,9 @@
import styled from "styled-components";
import { PrimaryButton } from "../../../../Buttons/PrimaryButton/PrimaryButton";

export const SaveButtonContainer = styled(PrimaryButton)`
@media screen and (max-width: 600px) {
width: 140px;
height: 45px;
}
`;

+ 10
- 23
src/components/Cards/OfferCard/OfferCard.js Прегледај датотеку

@@ -1,7 +1,6 @@
import React, { useMemo, useState } from "react";
import PropTypes from "prop-types";
import {
CheckButton,
DetailIcon,
DetailText,
EditIcon,
@@ -13,9 +12,6 @@ import {
OfferAuthorName,
OfferCardContainer,
OfferCategory,
OfferDescription,
OfferDescriptionText,
OfferDescriptionTitle,
OfferDetails,
OfferFlexContainer,
OfferImage,
@@ -34,13 +30,14 @@ import {
} from "./OfferCard.styled";
import DeleteOffer from "./DeleteOffer/DeleteOffer";
import { ReactComponent as Message } from "../../../assets/images/svg/mail.svg";
import selectedTheme from "../../../themes";
import { useHistory } from "react-router-dom";
import CreateOffer from "../CreateOfferCard/CreateOffer";
import { useSelector } from "react-redux";
import { selectUserId } from "../../../store/selectors/loginSelectors";
import useIsMobile from "../../../hooks/useIsMobile";
import { getImageUrl, variants } from "../../../util/helpers/imageUrlGetter";
import OfferDescription from "./OfferDescription/OfferDescription";
import CheckButton from "./CheckButton/CheckButton";

const OfferCard = (props) => {
const [deleteOfferModal, setDeleteOfferModal] = useState(false);
@@ -93,17 +90,20 @@ const OfferCard = (props) => {
}
halfwidth={props.halfwidth ? 1 : 0}
>
{/* This only shows on vertical offer card */}
<OfferTitleAboveImage
vertical={props.vertical}
onClick={() => routeToItem(props?.offer?._id)}
>
{props?.offer?.name}
</OfferTitleAboveImage>
{/* ^^^^^^^ */}
<OfferFlexContainer vertical={props.vertical}>
<OfferImageContainer vertical={props.vertical}>
<OfferImage
src={
props?.offer?.images
props?.offer?.images
? getImageUrl(
props?.offer?.images[0],
variants.offerCard,
@@ -151,24 +151,11 @@ const OfferCard = (props) => {
{!props.halfwidth ? (
<React.Fragment>
<Line />
<OfferDescription>
<OfferDescriptionTitle>Opis:</OfferDescriptionTitle>
<OfferDescriptionText>
{props?.offer?.description}
</OfferDescriptionText>
</OfferDescription>

<OfferDescription description={props?.offer?.description} />
<CheckButton
variant={props.sponsored ? "contained" : "outlined"}
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor={
props.sponsored ? "white" : selectedTheme.colors.primaryPurple
}
style={{ fontWeight: "600" }}
onClick={() => routeToItem(props?.offer?._id)}
>
Pogledaj proizvod
</CheckButton>
offerId={props?.offer?._id}
sponsored={props.sponsored}
/>
</React.Fragment>
) : (
<></>

+ 1
- 44
src/components/Cards/OfferCard/OfferCard.styled.js Прегледај датотеку

@@ -2,7 +2,6 @@ import { Box, Container, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../themes";
import { IconButton } from "../../Buttons/IconButton/IconButton";
import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton";
import { Icon } from "../../Icon/Icon";
import { ReactComponent as Eye } from "../../../assets/images/svg/eye-striked.svg";
import { ReactComponent as Remove } from "../../../assets/images/svg/trash.svg";
@@ -195,35 +194,7 @@ export const OfferViews = styled(Box)`
display: none;
`}
`;
export const OfferDescriptionTitle = styled(Box)`
font-family: ${selectedTheme.fonts.textFont};
font-size: 12px;
color: ${selectedTheme.colors.primaryDarkText};
line-height: 16px;
`;
export const OfferDescriptionText = styled(Box)`
font-family: ${selectedTheme.fonts.textFont};
font-size: 16px;
color: ${selectedTheme.colors.primaryDarkText};
line-height: 22px;
max-width: calc(100% - 230px);
max-height: 120px;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 5;
-webkit-box-orient: vertical;
@media (max-width: 1500px) {
display: none;
}
`;
export const OfferDescription = styled(Box)`
flex: 3;
margin: auto 0;
padding-left: 35px;
@media (max-width: 1500px) {
display: none;
}
`;

export const Line = styled(Box)`
border-left: 1px solid rgba(0, 0, 0, 0.15);
height: 100px;
@@ -249,20 +220,6 @@ export const DetailText = styled(Typography)`
top: -2px;
left: 3px;
`;
export const CheckButton = styled(PrimaryButton)`
width: 180px;
height: 48px;
position: absolute;
bottom: 9px;
right: 9px;
&:hover button {
background-color: ${selectedTheme.colors.primaryPurple} !important;
color: white !important;
}
@media (max-width: 650px) {
display: none;
}
`;
export const MessageIcon = styled(IconButton)`
${(props) => !props.showMessageIcon && "display: none;"}
width: 40px;

+ 26
- 0
src/components/Cards/OfferCard/OfferDescription/OfferDescription.js Прегледај датотеку

@@ -0,0 +1,26 @@
import React from "react";
import PropTypes from "prop-types";
import {
OfferDescriptionContainer,
OfferDescriptionText,
OfferDescriptionTitle,
} from "./OfferDescription.styled";
import { useTranslation } from "react-i18next";

const OfferDescription = (props) => {
const { t } = useTranslation();
return (
<OfferDescriptionContainer>
<OfferDescriptionTitle>
{t("offer.descriptionLabel")}
</OfferDescriptionTitle>
<OfferDescriptionText>{props.description}</OfferDescriptionText>
</OfferDescriptionContainer>
);
};

OfferDescription.propTypes = {
description: PropTypes.string,
};

export default OfferDescription;

+ 33
- 0
src/components/Cards/OfferCard/OfferDescription/OfferDescription.styled.js Прегледај датотеку

@@ -0,0 +1,33 @@
import { Box } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../../themes";

export const OfferDescriptionText = styled(Box)`
font-family: ${selectedTheme.fonts.textFont};
font-size: 16px;
color: ${selectedTheme.colors.primaryDarkText};
line-height: 22px;
max-width: calc(100% - 230px);
max-height: 120px;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 5;
-webkit-box-orient: vertical;
@media (max-width: 1500px) {
display: none;
}
`;
export const OfferDescriptionContainer = styled(Box)`
flex: 3;
margin: auto 0;
padding-left: 35px;
@media (max-width: 1500px) {
display: none;
}
`;
export const OfferDescriptionTitle = styled(Box)`
font-family: ${selectedTheme.fonts.textFont};
font-size: 12px;
color: ${selectedTheme.colors.primaryDarkText};
line-height: 16px;
`;

+ 0
- 1
src/components/Cards/OfferCard/SkeletonOfferCard/SkeletonOfferCard.js Прегледај датотеку

@@ -57,7 +57,6 @@ const SkeletonOfferCard = (props) => {
SkeletonOfferCard.propTypes = {
children: PropTypes.node,
skeleton: PropTypes.bool,
animationStage: PropTypes.number,
};

export default SkeletonOfferCard;

+ 25
- 0
src/components/Cards/ProfileCard/EditProfile/AppLinkField/AppLinkField.js Прегледај датотеку

@@ -0,0 +1,25 @@
import React from "react";
import PropTypes from "prop-types";
import { InputField, InputFieldLabel } from "../EditProfile.styled";
import { useTranslation } from "react-i18next";

const AppLinkField = (props) => {
const { t } = useTranslation();
return (
<>
<InputFieldLabel leftText={t("editProfile.applink").toUpperCase()} />
<InputField
name="firmApplink"
values={props.formik.values.firmApplink}
margin="normal"
fullWidth
/>
</>
);
};

AppLinkField.propTypes = {
formik: PropTypes.any,
};

export default AppLinkField;

+ 0
- 0
src/components/Cards/ProfileCard/EditProfile/AppLinkField/AppLinkField.styled.js Прегледај датотеку


+ 167
- 0
src/components/Cards/ProfileCard/EditProfile/EditProfile.js Прегледај датотеку

@@ -0,0 +1,167 @@
import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
import BackdropComponent from "../../../MUI/BackdropComponent";
import {
EditProfileContainer,
ProfileImageContainer,
BackButton,
CloseButton,
SaveButton,
ProfileHeader,
BasicInfo,
DetailsInfo,
ButtonsContainer,
ProfileImagePicker,
} from "./EditProfile.styled";
import selectedTheme from "../../../../themes";
import { useFormik } from "formik";
import { ReactComponent as ArrowBack } from "../../../../assets/images/svg/arrow-back.svg";
import { ReactComponent as CloseIcon } from "../../../../assets/images/svg/close-modal.svg";
import { useTranslation } from "react-i18next";
import {
editMineProfile,
fetchMineProfile,
} from "../../../../store/actions/profile/profileActions";
import { useDispatch, useSelector } from "react-redux";
import { selectUserId } from "../../../../store/selectors/loginSelectors";
import editProfileValidation from "../../../../validations/editProfileValidation";
import useIsMobile from "../../../../hooks/useIsMobile";
import { useMemo } from "react";
import editProfileInitialValues from "../../../../initialValues/editProfileInitialValues";
import FirmNameField from "./FirmNameField/FirmNameField";
import PIBField from "./PIBField/PIBField";
import LocationField from "./LocationField/LocationField";
import WebsiteField from "./WebsiteField/WebsiteField";
import AppLinkField from "./AppLinkField/AppLinkField";
import PhoneField from "./PhoneField/PhoneField";
import FormikErrorMessage from "./FormikErrorMessage/FormikErrorMessage";

const EditProfile = (props) => {
const [profileImage, setProfileImage] = useState(props.profile.image);
const [showBasic, setShowBasic] = useState(true);
const [showDetails, setShowDetails] = useState(true);
const { t } = useTranslation();
const dispatch = useDispatch();
const { isMobile } = useIsMobile();
const userId = useSelector(selectUserId);

useEffect(() => {
setShowDetails(!isMobile);
}, [isMobile]);

const handleApiResponseSuccess = () => {
dispatch(fetchMineProfile(userId));
props.reFetchProfile();
};

const handleSubmit = (values) => {
dispatch(editMineProfile({ ...values, handleApiResponseSuccess }));
props.closeModalHandler();
};
const initialValues = useMemo(
() => editProfileInitialValues(props?.profile),
[props?.profile]
);

const formik = useFormik({
initialValues,
validationSchema: editProfileValidation,
onSubmit: handleSubmit,
validateOnBlur: true,
enableReinitialize: true,
});

const closeEditModalHandler = () => {
props.closeModalHandler();
};

const showDetailsHandler = () => {
setShowDetails(!showDetails);
setShowBasic(!showBasic);
};

const setImage = (image) => {
setProfileImage(image);
};

return (
<>
<BackdropComponent
handleClose={closeEditModalHandler}
isLoading
position="fixed"
/>
<EditProfileContainer component="form" onSubmit={formik.handleSubmit}>
{!showBasic && (
<BackButton onClick={showDetailsHandler}>
<ArrowBack />
</BackButton>
)}
<ProfileImageContainer>
<ProfileImagePicker
image={profileImage}
setImage={setImage}
></ProfileImagePicker>
<ProfileHeader>{props.profile.company.name}</ProfileHeader>
</ProfileImageContainer>
<CloseButton onClick={closeEditModalHandler}>
<CloseIcon />
</CloseButton>
{showBasic && (
<BasicInfo>
<FirmNameField formik={formik} />
<PIBField formik={formik} />
<LocationField formik={formik} />
</BasicInfo>
)}
{showDetails && (
<DetailsInfo>
<WebsiteField formik={formik} />
<AppLinkField formik={formik} />
<PhoneField formik={formik} />
</DetailsInfo>
)}

<FormikErrorMessage formik={formik} />

<ButtonsContainer>
{isMobile && (
<>
<SaveButton
height="44px"
width="155px"
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor={selectedTheme.colors.primaryPurple}
onClick={showDetailsHandler}
>
{showDetails
? t("editProfile.showBasic")
: t("editProfile.showDetails")}
</SaveButton>
</>
)}
<SaveButton
type="submit"
variant="contained"
height={isMobile ? "44px" : "48px"}
width={isMobile ? "155px" : "335px"}
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor="white"
>
{t("common.save")}
</SaveButton>
</ButtonsContainer>
</EditProfileContainer>
</>
);
};

EditProfile.propTypes = {
children: PropTypes.node,
profile: PropTypes.any,
closeModalHandler: PropTypes.func,
setImage: PropTypes.func,
reFetchProfile: PropTypes.func,
};

export default EditProfile;

src/components/ProfileCard/EditProfile/EditProfile.styled.js → src/components/Cards/ProfileCard/EditProfile/EditProfile.styled.js Прегледај датотеку

@@ -1,9 +1,9 @@
import styled from "styled-components";
import { Box, TextField, Typography } from "@mui/material";
import ImagePicker from "../../ImagePicker/ImagePicker";
import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton";
import { Label } from "../../CheckBox/Label";
import selectedTheme from "../../../themes";
import ImagePicker from "../../../ImagePicker/ImagePicker";
import { PrimaryButton } from "../../../Buttons/PrimaryButton/PrimaryButton";
import { Label } from "../../../CheckBox/Label";
import selectedTheme from "../../../../themes";

export const EditProfileContainer = styled(Box)`
background-color: #fff;
@@ -120,29 +120,6 @@ export const InputField = styled(TextField)`
}
`;

export const InputFieldLabelLocation = styled(Label)`
position: relative;
bottom: -8px;
margin: 10px 0;
& label {
font-size: 12px;
font-weight: 600;
line-height: 20px;
color: #808080;
cursor: auto;
letter-spacing: 0.2px;
}

@media screen and (max-width: 600px) {
bottom: -12px;
margin: 5px 0 17px 0;
& label {
font-size: 9px;
margin-top: 0;
}
}
`;

export const SaveButton = styled(PrimaryButton)`
font-size: 12px;
letter-spacing: 1.5px;
@@ -158,14 +135,6 @@ export const ButtonsContainer = styled(Box)`
}
`;

export const ErrorMessage = styled(Typography)`
color: red;
font-family: ${selectedTheme.fonts.textFont};
position: relative;
top: 20px;
font-size: 14px;
`;

export const BasicInfo = styled(Box)``;

export const DetailsInfo = styled(Box)``;

+ 27
- 0
src/components/Cards/ProfileCard/EditProfile/FirmNameField/FirmNameField.js Прегледај датотеку

@@ -0,0 +1,27 @@
import React from "react";
import PropTypes from "prop-types";
import { InputField, InputFieldLabel } from "../EditProfile.styled";
import { useTranslation } from "react-i18next";

const FirmNameField = (props) => {
const { t } = useTranslation();
return (
<>
<InputFieldLabel leftText={t("common.labelFirm").toUpperCase()} />
<InputField
name="firmName"
value={props.formik.values.firmName}
onChange={props.formik.handleChange}
error={props.formik.touched.firmName && props.formik.errors.firmName}
margin="normal"
fullWidth
/>
</>
);
};

FirmNameField.propTypes = {
formik: PropTypes.any,
};

export default FirmNameField;

+ 0
- 0
src/components/Cards/ProfileCard/EditProfile/FirmNameField/FirmNameField.styled.js Прегледај датотеку


+ 28
- 0
src/components/Cards/ProfileCard/EditProfile/FormikErrorMessage/FormikErrorMessage.js Прегледај датотеку

@@ -0,0 +1,28 @@
import React from "react";
import PropTypes from "prop-types";
import { ErrorMessage } from "./FormikErrorMessage.styled";

const FormikErrorMessage = (props) => {
return (
<>
{props.formik.errors.firmName && props.formik.touched.firmName ? (
<ErrorMessage>{props.formik.errors.firmName}</ErrorMessage>
) : props.formik.errors.firmPIB && props.formik.touched.firmPIB ? (
<ErrorMessage>{props.formik.errors.firmPIB}</ErrorMessage>
) : props.formik.errors.firmLocation &&
props.formik.touched.firmLocation ? (
<ErrorMessage>{props.formik.errors.firmLocation}</ErrorMessage>
) : props.formik.errors.firmPhone && props.formik.touched.firmPhone ? (
<ErrorMessage>{props.formik.errors.firmPhone}</ErrorMessage>
) : (
<></>
)}
</>
);
};

FormikErrorMessage.propTypes = {
formik: PropTypes.any,
};

export default FormikErrorMessage;

+ 11
- 0
src/components/Cards/ProfileCard/EditProfile/FormikErrorMessage/FormikErrorMessage.styled.js Прегледај датотеку

@@ -0,0 +1,11 @@
import { Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../../../themes";

export const ErrorMessage = styled(Typography)`
color: red;
font-family: ${selectedTheme.fonts.textFont};
position: relative;
top: 20px;
font-size: 14px;
`;

+ 42
- 0
src/components/Cards/ProfileCard/EditProfile/LocationField/LocationField.js Прегледај датотеку

@@ -0,0 +1,42 @@
import React from "react";
import PropTypes from "prop-types";
import AutoSuggestTextField from "../../../../TextFields/AutoSuggestTextField/AutoSuggestTextField";
import { InputFieldLabelLocation } from "./LocationField.styled";
import { useDispatch, useSelector } from "react-redux";
import { selectLocations } from "../../../../../store/selectors/locationsSelectors";
import { useEffect } from "react";
import { fetchLocations } from "../../../../../store/actions/locations/locationsActions";
import { useTranslation } from "react-i18next";

const LocationField = (props) => {
const { t } = useTranslation();
const locations = useSelector(selectLocations);
const dispatch = useDispatch();
useEffect(() => {
if (locations?.length === 0) {
dispatch(fetchLocations());
}
}, [locations]);

return (
<>
<InputFieldLabelLocation
leftText={t("common.labelLocation").toUpperCase()}
/>
<AutoSuggestTextField
editLocation
data={locations.map((item) => ({ name: item.city }))}
value={props.formik.values.firmLocation}
onChange={(event, { newValue }) =>
props.formik.setFieldValue("firmLocation", newValue)
}
/>
</>
);
};

LocationField.propTypes = {
formik: PropTypes.any,
};

export default LocationField;

+ 25
- 0
src/components/Cards/ProfileCard/EditProfile/LocationField/LocationField.styled.js Прегледај датотеку

@@ -0,0 +1,25 @@
import styled from "styled-components";
import { Label } from "../../../../CheckBox/Label";

export const InputFieldLabelLocation = styled(Label)`
position: relative;
bottom: -8px;
margin: 10px 0;
& label {
font-size: 12px;
font-weight: 600;
line-height: 20px;
color: #808080;
cursor: auto;
letter-spacing: 0.2px;
}

@media screen and (max-width: 600px) {
bottom: -12px;
margin: 5px 0 17px 0;
& label {
font-size: 9px;
margin-top: 0;
}
}
`;

+ 29
- 0
src/components/Cards/ProfileCard/EditProfile/PIBField/PIBField.js Прегледај датотеку

@@ -0,0 +1,29 @@
import React from "react";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
import { InputField, InputFieldLabel } from "../EditProfile.styled";

const PIBField = (props) => {
const { t } = useTranslation();
return (
<>
<InputFieldLabel leftText={t("common.labelPIB")} />
<InputField
name="firmPIB"
type="number"
value={props.formik.values.firmPIB}
onChange={props.formik.handleChange}
error={props.formik.touched.firmPIB && props.formik.errors.firmPIB}
margin="normal"
fullWidth
disabled
/>
</>
);
};

PIBField.propTypes = {
formik: PropTypes.any,
};

export default PIBField;

+ 0
- 0
src/components/Cards/ProfileCard/EditProfile/PIBField/PIBField.styled.js Прегледај датотеку


+ 39
- 0
src/components/Cards/ProfileCard/EditProfile/PhoneField/PhoneField.js Прегледај датотеку

@@ -0,0 +1,39 @@
import React from "react";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
import { InputField, InputFieldLabel } from "../EditProfile.styled";

const PhoneField = (props) => {
const { t } = useTranslation();
return (
<>
<InputFieldLabel leftText={t("editProfile.phoneNumber").toUpperCase()} />
<InputField
type="number"
name="firmPhone"
value={props.formik.values.firmPhone}
onChange={(event) => {
props.formik.setFieldValue("firmPhone", event.target.value);
}}
error={props.formik.touched.firmPhone && props.formik.errors.firmPhone}
margin="normal"
fullWidth
onInput={(e) => {
e.target.value =
e.target.value[0] === "0" && e.target.value.length > 1
? "0" +
String(
Math.max(0, parseInt(e.target.value)).toString().slice(0, 14)
)
: Math.max(0, parseInt(e.target.value)).toString().slice(0, 14);
}}
/>
</>
);
};

PhoneField.propTypes = {
formik: PropTypes.any,
};

export default PhoneField;

+ 0
- 0
src/components/Cards/ProfileCard/EditProfile/PhoneField/PhoneField.styled.js Прегледај датотеку


+ 29
- 0
src/components/Cards/ProfileCard/EditProfile/WebsiteField/WebsiteField.js Прегледај датотеку

@@ -0,0 +1,29 @@
import React from "react";
import PropTypes from "prop-types";
import { InputField, InputFieldLabel } from "../EditProfile.styled";
import { useTranslation } from "react-i18next";

const WebsiteField = (props) => {
const { t } = useTranslation();
return (
<>
<InputFieldLabel
leftText={t("editProfile.website").toUpperCase()}
labelWebsite
/>
<InputField
name="firmWebsite"
value={props.formik.values.firmWebsite}
onChange={props.formik.handleChange}
margin="normal"
fullWidth
/>
</>
);
};

WebsiteField.propTypes = {
formik: PropTypes.any,
};

export default WebsiteField;

+ 0
- 0
src/components/Cards/ProfileCard/EditProfile/WebsiteField/WebsiteField.styled.js Прегледај датотеку


src/components/ProfileCard/ProfileCard.js → src/components/Cards/ProfileCard/ProfileCard.js Прегледај датотеку

@@ -13,23 +13,23 @@ import {
} from "./ProfileCard.styled";
import PersonOutlineIcon from "@mui/icons-material/PersonOutline";
import { useRouteMatch } from "react-router-dom";
import { fetchProfile } from "../../store/actions/profile/profileActions";
import { fetchProfile } from "../../../store/actions/profile/profileActions";
import { useDispatch, useSelector } from "react-redux";
import { useEffect } from "react";
import { selectProfile } from "../../store/selectors/profileSelectors";
import { selectUserId } from "../../store/selectors/loginSelectors";
import { selectProfile } from "../../../store/selectors/profileSelectors";
import { selectUserId } from "../../../store/selectors/loginSelectors";
import { useState } from "react";
import { fetchProfileOffers } from "../../store/actions/offers/offersActions";
import { fetchProfileOffers } from "../../../store/actions/offers/offersActions";
import EditProfile from "./EditProfile/EditProfile";
import ProfileMainInfo from "./ProfileMainInfo/ProfileMainInfo";
import ProfileContact from "./ProfileContact/ProfileContact";
import ProfileStats from "./ProfileStats/ProfileStats";
import { useTranslation } from "react-i18next";
import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors";
import { PROFILE_SCOPE } from "../../store/actions/profile/profileActionConstants";
import { selectIsLoadingByActionType } from "../../../store/selectors/loadingSelectors";
import { PROFILE_SCOPE } from "../../../store/actions/profile/profileActionConstants";
import SkeletonProfileCard from "./SkeletonProfileCard/SkeletonProfileCard";
import { useMemo } from "react";
import companyData from "../../notFoundData/companyData";
import companyData from "../../../notFoundData/companyData";

const ProfileCard = () => {
const [isMyProfile, setIsMyProfile] = useState(false);
@@ -51,7 +51,6 @@ const ProfileCard = () => {
return companyData;
}, [profileFromRedux]);

console.log("profile", profile);

useEffect(() => {
if (idProfile?.length > 0) {

src/components/ProfileCard/ProfileCard.styled.js → src/components/Cards/ProfileCard/ProfileCard.styled.js Прегледај датотеку


Неке датотеке нису приказане због велике количине промена

Loading…
Откажи
Сачувај