diff --git a/common/config/main.php b/common/config/main.php index 07b6b0d..03dcf3b 100755 --- a/common/config/main.php +++ b/common/config/main.php @@ -39,6 +39,10 @@ 'class' => 'yii\i18n\PhpMessageSource', 'basePath' => '@artbox/weblog/messages', ], + 'order' => [ + 'class' => 'yii\i18n\PhpMessageSource', + 'basePath' => '@artbox/order/messages', + ], ], ], 'filedb' => [ diff --git a/common/models/PasswordResetRequestForm.php b/common/models/PasswordResetRequestForm.php new file mode 100644 index 0000000..f621b3e --- /dev/null +++ b/common/models/PasswordResetRequestForm.php @@ -0,0 +1,78 @@ + '\artbox\order\models\Customer', + 'filter' => [ 'status' => Customer::STATUS_ACTIVE ], + 'message' => 'There is no user with this email address.', + ], + ]; + } + /** + * Sends an email with a link, for resetting the password. + * + * @return bool whether the email was send + */ + public function sendEmail() + { + /* @var $user Customer */ + $user = Customer::findOne( + [ + 'status' => Customer::STATUS_ACTIVE, + 'email' => $this->email, + ] + ); + if (!$user) { + return false; + } + + if (!Customer::isPasswordResetTokenValid($user->password_reset_token)) { + $user->generatePasswordResetToken(); + if (!$user->save()) { + return false; + } + } + return Yii::$app->mailer->compose( + [ + 'html' => 'passwordResetToken-html', + 'text' => 'passwordResetToken-text', + ], + [ 'user' => $user ] + ) + ->setFrom([ Yii::$app->params[ 'supportEmail' ] => Yii::$app->name . ' robot' ]) + ->setTo($this->email) + ->setSubject('Password reset for ' . Yii::$app->name) + ->send(); + } + } \ No newline at end of file diff --git a/common/models/ResetPasswordForm.php b/common/models/ResetPasswordForm.php new file mode 100644 index 0000000..358d36e --- /dev/null +++ b/common/models/ResetPasswordForm.php @@ -0,0 +1,72 @@ +_user = Customer::findByPasswordResetToken($token); + if (!$this->_user) { + throw new InvalidParamException('Wrong password reset token.'); + } + parent::__construct($config); + } + + /** + * @inheritdoc + */ + public function rules() + { + return [ + [ + 'password', + 'required', + ], + [ + 'password', + 'string', + 'min' => 6, + ], + ]; + } + + /** + * Resets password. + * + * @return bool if password was reset. + */ + public function resetPassword() + { + $user = $this->_user; + $user->setPassword($this->password); + $user->removePasswordResetToken(); + + return $user->save(false); + } + } \ No newline at end of file diff --git a/common/models/SignupForm.php b/common/models/SignupForm.php new file mode 100644 index 0000000..867fe3d --- /dev/null +++ b/common/models/SignupForm.php @@ -0,0 +1,99 @@ + '\artbox\order\models\Customer', + 'message' => 'This username has already been taken.', + ], + [ + 'username', + 'string', + 'min' => 2, + 'max' => 255, + ], + + [ + 'email', + 'trim', + ], + [ + 'email', + 'required', + ], + [ + 'email', + 'email', + ], + [ + 'email', + 'string', + 'max' => 255, + ], + [ + 'email', + 'unique', + 'targetClass' => '\artbox\order\models\Customer', + 'message' => 'This email address has already been taken.', + ], + + [ + 'password', + 'required', + ], + [ + 'password', + 'string', + 'min' => 6, + ], + ]; + } + + /** + * Signs user up. + * + * @return \artbox\order\models\Customer|null the saved model or null if saving fails + */ + public function signup() + { + if (!$this->validate()) { + return null; + } + + $user = new Customer(); + $user->username = $this->username; + $user->email = $this->email; + $user->setPassword($this->password); + $user->generateAuthKey(); + + return $user->save() ? $user : null; + } + } \ No newline at end of file diff --git a/frontend/assets/AppAsset.php b/frontend/assets/AppAsset.php index 697ef92..f7e2144 100755 --- a/frontend/assets/AppAsset.php +++ b/frontend/assets/AppAsset.php @@ -33,6 +33,7 @@ 'yii\web\YiiAsset', 'rmrevin\yii\fontawesome\AssetBundle', 'yii\bootstrap\BootstrapPluginAsset', + 'yii\widgets\PjaxAsset', 'artbox\order\assets\BasketAsset', ]; } diff --git a/frontend/config/main.php b/frontend/config/main.php index 67f489e..1d60719 100755 --- a/frontend/config/main.php +++ b/frontend/config/main.php @@ -1,6 +1,7 @@ dirname(__DIR__), 'bootstrap' => [ 'log' ], 'controllerNamespace' => 'frontend\controllers', + 'controllerMap' => [ + 'basket' => 'artbox\order\controllers\BasketController', + ], 'components' => [ 'request' => [ 'class' => LanguageRequest::className(), @@ -22,7 +26,7 @@ 'baseUrl' => '/', ], 'user' => [ - 'identityClass' => 'common\models\User', + 'identityClass' => 'artbox\order\models\Customer', 'enableAutoLogin' => true, 'identityCookie' => [ 'name' => '_identity-frontend', @@ -69,6 +73,9 @@ 'robots.txt' => 'site/robots', ], ], + 'basket' => [ + 'class' => Basket::className(), + ], ], 'params' => $params, ]; diff --git a/frontend/config/params.php b/frontend/config/params.php index fa597b5..90de023 100755 --- a/frontend/config/params.php +++ b/frontend/config/params.php @@ -2,3 +2,4 @@ return [ 'adminEmail' => 'admin@example.com', ]; + \ No newline at end of file diff --git a/frontend/controllers/CheckoutController.php b/frontend/controllers/CheckoutController.php new file mode 100755 index 0000000..84bed77 --- /dev/null +++ b/frontend/controllers/CheckoutController.php @@ -0,0 +1,190 @@ +get('basket'); + $data = $basket->getData(); + $variants = []; + if (!empty($data)) { + $variants = $basket->findModels(array_keys($data)); + } + return $this->render( + 'index', + [ + 'basket' => $basket, + 'variants' => $variants, + ] + ); + } + + public function actionInfo() + { + $model = new Order( + [ + 'scenario' => Order::SCENARIO_INFO, + ] + ); + if (!\Yii::$app->user->isGuest) { + /** + * @var \artbox\order\models\Customer $user + */ + $user = \Yii::$app->user->identity; + $model->name = $user->name; + $model->email = $user->email; + $model->phone = $user->phone; + $model->city = $user->city; + $model->address = $user->address; + } + $model->loadActive(); + if ($model->load(\Yii::$app->request->post()) && $model->validate()) { + $model->saveActive(); + return $this->redirect([ 'delivery' ]); + } + return $this->render( + 'info', + [ + 'model' => $model, + ] + ); + } + + public function actionDelivery() + { + $model = new Order( + [ + 'scenario' => Order::SCENARIO_INFO, + ] + ); + if (!empty($order = \Yii::$app->session->get('order')) && $model->load($order, '') && $model->validate()) { + $model->scenario = Order::SCENARIO_DELIVERY; + $model->loadActive(); + if ($model->load(\Yii::$app->request->post()) && $model->validate()) { + $model->saveActive(); + return $this->redirect([ 'payment' ]); + } + } else { + return $this->redirect([ 'info' ]); + } + $deliveries = Delivery::find() + ->with('lang') + ->where([ 'status' => true ]) + ->orderBy([ 'sort' => SORT_ASC ]) + ->all(); + return $this->render( + 'delivery', + [ + 'model' => $model, + 'deliveries' => $deliveries, + ] + ); + } + + public function actionPayment() + { + $model = new Order( + [ + 'scenario' => Order::SCENARIO_INFO, + ] + ); + $order = \Yii::$app->session->get('order'); + if (!empty($model)) { + if ($model->load($order, '') && $model->validate()) { + $model->scenario = Order::SCENARIO_DELIVERY; + if ($model->load($order, '') && $model->validate()) { + $model->scenario = Order::SCENARIO_PAYMENT; + $model->loadActive(); + if ($model->load(\Yii::$app->request->post()) && $model->validate()) { + $model->saveActive(); + return $this->redirect('confirm'); + } else { + $payments = Payment::find() + ->with('lang') + ->where([ 'status' => true ]) + ->orderBy([ 'sort' => SORT_ASC ]) + ->all(); + return $this->render( + 'payment', + [ + 'model' => $model, + 'payments' => $payments, + ] + ); + } + } + } + } + return $this->redirect( + 'delivery' + ); + } + + public function actionConfirm() + { + $model = new Order(); + $order = \Yii::$app->session->get('order'); + $model->load($order, ''); + if (!$model->validate()) { + return $this->redirect([ 'payment' ]); + } + if (\Yii::$app->request->isPost) { + $model->label_id = 1; + $model->save(false); + /** + * @var \artbox\order\models\Basket $basket + */ + $basket = \Yii::$app->get('basket'); + foreach ($basket->findModels(array_keys($basket->getData())) as $variant) { + $orderProduct = new OrderProduct( + [ + 'order_id' => $model->id, + 'variant_id' => $variant->id, + 'sku' => $variant->sku, + 'price' => $variant->price, + 'count' => $basket->getItem($variant->id)[ 'count' ], + ] + ); + $orderProduct->save(); + } + \Yii::$app->session->remove('order'); + $basket->clear(); + return $this->redirect([ 'site/index' ]); + } + return $this->render( + 'confirm', + [ + 'model' => $model, + ] + ); + } + + public function beforeAction($action) + { + /** + * @var \artbox\order\models\Basket $basket + */ + $basket = \Yii::$app->get('basket'); + if ($action->id !== 'index' && empty($basket->getData())) { + return $this->redirect([ 'site/index' ]); + } + return parent::beforeAction($action); + } + } + \ No newline at end of file diff --git a/frontend/controllers/PageController.php b/frontend/controllers/PageController.php index 2c4f8fb..8cd4b40 100755 --- a/frontend/controllers/PageController.php +++ b/frontend/controllers/PageController.php @@ -3,9 +3,6 @@ use artbox\core\components\SeoComponent; use artbox\core\models\Page; - use yii\helpers\Json; - use yii\helpers\Url; - use yii\helpers\VarDumper; use yii\web\Controller; use yii\web\NotFoundHttpException; use Yii; diff --git a/frontend/controllers/SiteController.php b/frontend/controllers/SiteController.php index 8803b2c..a38fc76 100755 --- a/frontend/controllers/SiteController.php +++ b/frontend/controllers/SiteController.php @@ -1,12 +1,18 @@ response->format = Response::FORMAT_JSON; - if (empty( Yii::$app->request->post() )) { + if (empty(Yii::$app->request->post())) { throw new BadRequestHttpException(); } else { $model = new Feedback(); @@ -173,4 +179,103 @@ } } } + + public function actionLogin() + { + if (!\Yii::$app->user->isGuest) { + return $this->redirect([ 'index' ]); + } + + $loginForm = new LoginForm(); + $signupForm = new SignupForm(); + if ($loginForm->load(\Yii::$app->request->post()) && $loginForm->login()) { + if (!empty($loginForm->returnUrl)) { + return $this->redirect($loginForm->returnUrl); + } else { + return $this->redirect([ 'index' ]); + } + } + if ($signupForm->load(\Yii::$app->request->post())) { + if ($user = $signupForm->signup()) { + if (\Yii::$app->getUser() + ->login($user) + ) { + return $this->redirect([ 'index' ]); + } + } + } + return $this->render( + 'login', + [ + 'loginForm' => $loginForm, + 'signupForm' => $signupForm, + ] + ); + } + + public function actionLogout() + { + \Yii::$app->user->logout(); + + return $this->redirect([ 'index' ]); + } + + /** + * Requests password reset. + * + * @return mixed + */ + public function actionRequestPasswordReset() + { + $model = new PasswordResetRequestForm(); + if ($model->load(Yii::$app->request->post()) && $model->validate()) { + if ($model->sendEmail()) { + Yii::$app->session->setFlash('success', 'Check your email for further instructions.'); + + return $this->redirect([ 'index' ]); + } else { + Yii::$app->session->setFlash( + 'error', + 'Sorry, we are unable to reset password for the provided email address.' + ); + } + } + + return $this->render( + 'requestPasswordResetToken', + [ + 'model' => $model, + ] + ); + } + + /** + * Resets password. + * + * @param string $token + * + * @return mixed + * @throws BadRequestHttpException + */ + public function actionResetPassword($token) + { + try { + $model = new ResetPasswordForm($token); + } catch (InvalidParamException $e) { + throw new BadRequestHttpException($e->getMessage()); + } + + if ($model->load(Yii::$app->request->post()) && $model->validate() && $model->resetPassword()) { + Yii::$app->session->setFlash('success', 'New password saved.'); + + return $this->redirect([ 'index' ]); + } + + return $this->render( + 'resetPassword', + [ + 'model' => $model, + ] + ); + } } diff --git a/frontend/models/Order.php b/frontend/models/Order.php new file mode 100644 index 0000000..0cb2f66 --- /dev/null +++ b/frontend/models/Order.php @@ -0,0 +1,126 @@ + [ + 'name', + 'phone', + 'email', + 'city', + 'address', + 'comment', + ], + self::SCENARIO_DELIVERY => [ + 'delivery_id', + ], + self::SCENARIO_PAYMENT => [ + 'payment_id', + ], + ] + ); + } + + /** + * @inheritdoc + */ + public function rules() + { + return [ + [ + [ + 'name', + 'phone', + 'email', + 'delivery_id', + 'payment_id', + ], + 'required', + ], + [ + [ + 'name', + 'phone', + 'email', + 'city', + 'address', + ], + 'string', + 'max' => 255, + ], + [ + [ + 'comment', + ], + 'string', + ], + [ + [ + 'delivery_id', + 'payment_id', + ], + 'integer', + ], + [ + [ + 'delivery_id', + ], + 'exist', + 'targetClass' => Delivery::className(), + 'targetAttribute' => 'id', + ], + [ + [ + 'payment_id', + ], + 'exist', + 'targetClass' => Payment::className(), + 'targetAttribute' => 'id', + ], + ]; + } + + /** + * Save active attributes to session variable 'order' + */ + public function saveActive() + { + $order = \Yii::$app->session->get('order', []); + foreach ($this->activeAttributes() as $attribute) { + $order[ $attribute ] = $this->getAttribute($attribute); + } + \Yii::$app->session[ 'order' ] = $order; + } + + /** + * Load active attributes from session variable 'order' + */ + public function loadActive() + { + $order = \Yii::$app->session->get('order'); + if (!empty($order)) { + foreach ($this->activeAttributes() as $attribute) { + if (!empty($order[ $attribute ])) { + $this->setAttribute($attribute, $order[ $attribute ]); + } + } + } + } + } \ No newline at end of file diff --git a/frontend/views/basket/cart.php b/frontend/views/basket/cart.php new file mode 100755 index 0000000..d706fc5 --- /dev/null +++ b/frontend/views/basket/cart.php @@ -0,0 +1,27 @@ + + + 'sub-title', + ] + ), + [ + '/checkout/index', + ], + [ + 'class' => 'cart-item-link', + ] + ); +?> diff --git a/frontend/views/basket/modal_items.php b/frontend/views/basket/modal_items.php new file mode 100755 index 0000000..0df3838 --- /dev/null +++ b/frontend/views/basket/modal_items.php @@ -0,0 +1,10 @@ +

variants[ 0 ]->stock && $product->variants[ 0 ]->price) { + echo Html::a( + Html::tag( + 'i', + '', + [ + 'class' => 'fa fa-shopping-cart', + ] + ) . \Yii::t('app', 'В корзину'), + '#', [ - 'class' => 'fa fa-shopping-cart', + 'class' => 'btn btn-template-main add-to-basket', + 'data-id' => $product->variants[ 0 ]->id, ] - ) . \Yii::t('app', 'В корзину'), - '#', - [ 'class' => 'btn btn-template-main' ] - ); + ); + } else { + echo Html::a( + \Yii::t('app', 'Нет в наличии'), + '#', + [ + 'class' => 'btn btn-info disabled', + 'data-id' => $product->variants[ 0 ]->id, + ] + ); + } ?>

diff --git a/frontend/views/checkout/confirm.php b/frontend/views/checkout/confirm.php new file mode 100644 index 0000000..fc801df --- /dev/null +++ b/frontend/views/checkout/confirm.php @@ -0,0 +1,248 @@ +formatter; + $basket = \Yii::$app->get('basket'); + $sum = 0; + $sumDiscount = 0; + $variants = $basket->findModels(array_keys($basket->getData())); + foreach ($variants as $variant) { + $count = $basket->getItem($variant->id)[ 'count' ]; + $sum += $variant->price * $count; + if (!empty($variant->price_old)) { + $sumDiscount += ( $variant->price_old - $variant->price ) * $count; + } + } +?> +
+
+ +
+ +
+ +
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ product->image->getPath()) + ->fillResize(50, 50) + ->renderImage( + [ + 'alt' => $variant->product->lang->title, + 'title' => $variant->product->lang->title, + ] + ), + [ + 'product/view', + 'id' => $variant->product->id, + ], + [ 'target' => '_blank' ] + ) + ?> + + product->lang->title, + [ + 'product/view', + 'id' => $variant->product->id, + ], + [ 'target' => '_blank' ] + ) + ?> + getItem($variant->id))) { + echo $item[ 'count' ]; + } + ?>price ? : 0 ) . ' грн.'; ?>price_old - $variant->price ) ? : 0 ) . ' грн.'; ?>price * $item[ 'count' ] . ' грн.'; ?>
грн.
+ +
+ +
+ + + + +
+ + + +
+ + +
+
+
+

+
+

+ +
+ + + + + + + + + + + + + + + + + + + +
грн.
грн.
delivery->value; ?> грн.
delivery->value; ?> грн.
+
+
+
+ +
+ + +
+ +
diff --git a/frontend/views/checkout/delivery.php b/frontend/views/checkout/delivery.php new file mode 100644 index 0000000..8071e3b --- /dev/null +++ b/frontend/views/checkout/delivery.php @@ -0,0 +1,238 @@ +formatter; + $basket = \Yii::$app->get('basket'); + $sum = 0; + $sumDiscount = 0; + foreach ($basket->findModels(array_keys($basket->getData())) as $variant) { + $count = $basket->getItem($variant->id)[ 'count' ]; + $sum += $variant->price * $count; + if (!empty($variant->price_old)) { + $sumDiscount += ( $variant->price_old - $variant->price ) * $count; + } + } +?> +
+
+ +
+ +
+ +
+ + + + +
+
+ hasErrors()) { + echo Html::tag( + 'p', + \Yii::t('app', 'Please choose delivery method.'), + [ + 'class' => 'text-danger', + ] + ); + } + foreach ($deliveries as $index => $delivery) { + ?> +
+
+ +
+ field( + $model, + 'delivery_id', + [ + 'options' => [ + 'class' => 'form-group order-radio', + ], + ] + ) + ->radio( + [ + 'uncheck' => ( $index === 0 ) ? 0 : null, + 'label' => null, + 'tag' => false, + 'value' => $delivery->id, + ] + ) + ->label(false) + ->error(false); + ?> +

lang->title; ?>

+
+ +

lang->description; ?>

+ +
+
+ +
+ + +
+ + + + +
+ + + +
+ + +
+
+
+

Итоговый счет

+
+

+ +
+ + + + + + + + + + + + + + + +
asDecimal($sum, 2); ?>
asDecimal($sumDiscount, 2); ?>
asDecimal($sum, 2); ?>
+
+
+
+ + +
+ + +
+ +
diff --git a/frontend/views/checkout/index.php b/frontend/views/checkout/index.php new file mode 100644 index 0000000..a8fd618 --- /dev/null +++ b/frontend/views/checkout/index.php @@ -0,0 +1,456 @@ +formatter; + $sum = 0; + $sumDiscount = 0; + foreach ($variants as $variant) { + $count = $basket->getItem($variant->id)[ 'count' ]; + $sum += $variant->price * $count; + if (!empty($variant->price_old)) { + $sumDiscount += ( $variant->price_old - $variant->price ) * $count; + } + } +?> +
+
+
+
+ +
+

+ +
+ +
+ + + + + + + + + + + + getItem($variant->id)[ 'count' ]; + ?> + + + + + + + + + + + + + + + + + +
+ product->image->getPath()) + ->fillResize(50, 50) + ->renderImage( + [ + 'alt' => $variant->product->lang->title, + 'title' => $variant->product->lang->title, + ] + ), + [ + '/product/view', + 'id' => $variant->product->id, + ], + [ + 'target' => '_blank', + ] + ); + ?> + + product->lang->title, + [ + '/product/view', + 'id' => $variant->product->id, + ], + [ + 'target' => '_blank', + ] + ); + ?> + + 'form-control increase-product-basket', + ] + ); + ?> + + asDecimal($variant->price ? : 0, 2); + ?> + + price_old)) { + echo $formatter->asDecimal($variant->price_old - $variant->price, 2); + } else { + echo $formatter->asDecimal(0, 2); + } + ?> + + asDecimal( + ( $variant->price ? : 0 ) * $count, + 2 + ); + ?> + +
asDecimal($sum, 2); ?>
+ +
+ + + + +
+ + +
+ + +
+
+
+

Итоговый счет

+
+

+ +
+ + + + + + + + + + + + + + + +
asDecimal($sum, 2); ?>
asDecimal($sumDiscount, 2); ?>
asDecimal($sum, 2); ?>
+
+
+
+ + +
+
+
+

Смотрите также

+
+ + +
+
+
+
\ No newline at end of file diff --git a/frontend/views/checkout/info.php b/frontend/views/checkout/info.php new file mode 100644 index 0000000..1ebc0a0 --- /dev/null +++ b/frontend/views/checkout/info.php @@ -0,0 +1,258 @@ +formatter; + $basket = \Yii::$app->get('basket'); + $sum = 0; + $sumDiscount = 0; + foreach ($basket->findModels(array_keys($basket->getData())) as $variant) { + $count = $basket->getItem($variant->id)[ 'count' ]; + $sum += $variant->price * $count; + if (!empty($variant->price_old)) { + $sumDiscount += ( $variant->price_old - $variant->price ) * $count; + } + } +?> +
+
+ +
+ +
+ +
+ + + + +
+ user->isGuest) { + ?> + + +
+
+ field($model, 'name') + ->textInput(); + ?> +
+
+
+ + +
+
+ field($model, 'city') + ->textInput(); + ?> +
+
+ field($model, 'address') + ->textInput(); + ?> +
+
+ + +
+
+ field($model, 'phone') + ->textInput(); + ?> +
+
+ field($model, 'email') + ->textInput(); + ?> +
+
+ +
+
+ field($model, 'comment') + ->textarea( + [ + 'rows' => 4, + ] + ); + ?> +
+
+ +
+ + + +
+ + + +
+ + +
+
+
+

Итоговый счет

+
+

+ +
+ + + + + + + + + + + + + + + +
asDecimal($sum, 2); ?>
asDecimal($sumDiscount, 2); ?>
asDecimal($sum, 2); ?>
+
+
+
+ + +
+ + +
+ +
diff --git a/frontend/views/checkout/payment.php b/frontend/views/checkout/payment.php new file mode 100644 index 0000000..a3aa112 --- /dev/null +++ b/frontend/views/checkout/payment.php @@ -0,0 +1,235 @@ +formatter; + $basket = \Yii::$app->get('basket'); + $sum = 0; + $sumDiscount = 0; + foreach ($basket->findModels(array_keys($basket->getData())) as $variant) { + $count = $basket->getItem($variant->id)[ 'count' ]; + $sum += $variant->price * $count; + if (!empty($variant->price_old)) { + $sumDiscount += ( $variant->price_old - $variant->price ) * $count; + } + } +?> +
+
+ +
+ +
+ +
+ + + + +
+
+ hasErrors()) { + echo Html::tag( + 'p', + \Yii::t('app', 'Please choose payment method.'), + [ + 'class' => 'text-danger', + ] + ); + } + foreach ($payments as $index => $payment) { + ?> +
+
+ +
+ field( + $model, + 'payment_id', + [ + 'options' => [ + 'class' => 'form-group order-radio', + ], + ] + ) + ->radio( + [ + 'uncheck' => ( $index === 0 ) ? 0 : null, + 'label' => null, + 'tag' => false, + 'value' => $payment->id, + ] + ) + ->label(false) + ->error(false); + ?> +

lang->title; ?>

+
+ +

lang->description; ?>

+ +
+
+ +
+ + +
+ + + + +
+ + + +
+ + +
+
+
+

Итоговый счет

+
+

+ +
+ + + + + + + + + + + + + + + +
asDecimal($sum, 2); ?>
asDecimal($sumDiscount, 2); ?>
asDecimal($sum, 2); ?>
+
+
+
+ + +
+ + +
+ +
diff --git a/frontend/views/layouts/main.php b/frontend/views/layouts/main.php index 0d7b7f4..fdec370 100755 --- a/frontend/views/layouts/main.php +++ b/frontend/views/layouts/main.php @@ -23,6 +23,9 @@ use yii\widgets\Breadcrumbs; AppAsset::register($this); + /** + * @var \artbox\order\models\Customer $user + */ $user = \Yii::$app->user->identity; $seo = Yii::$app->get('seo'); $feedback = new Feedback(); @@ -140,8 +143,16 @@ _________________________________________________________ -->
- - Вход + user->isGuest) { + ?> + + Вход + username, [ 'account/index' ]); + } + ?>
@@ -240,7 +251,7 @@ _________________________________________________________ -->
- 0 + 0 ] ), [ - '/basket/index', + '/checkout/index', ], [ 'class' => 'cart-item-link', @@ -332,64 +343,75 @@ _________________________________________________________ --> - - + diff --git a/frontend/views/product/view.php b/frontend/views/product/view.php index 139106c..6cd0de6 100755 --- a/frontend/views/product/view.php +++ b/frontend/views/product/view.php @@ -171,21 +171,54 @@

sku; ?>

Цена:price ? : 0; ?> грн  - - + stock && $variant->price) { + echo Html::a( + Html::tag( + 'i', + '', + [ + 'class' => 'fa fa-shopping-cart', + ] + ) . \Yii::t('app', 'Добавить в корзину'), + '#', + [ + 'class' => 'btn btn-success add-to-basket', + 'data-id' => $variant->id, + ] + ); + } else { + echo Html::a( + \Yii::t('app', 'Нет в наличии'), + '#', + [ + 'class' => 'btn btn-info disabled', + 'data-id' => $variant->id, + ] + ); + } + ?> + + + */ + ?>


- - -   + + +   + */ + ?>

diff --git a/frontend/views/site/_slider_product.php b/frontend/views/site/_slider_product.php index 3a193b0..0080230 100755 --- a/frontend/views/site/_slider_product.php +++ b/frontend/views/site/_slider_product.php @@ -5,89 +5,103 @@ use yii\web\View; /** - * @var View $this - * @var Product $product + * @var View $this + * @var Product $product */ ?>
-
-
- image ? $product->image->getPath() : '@frontend/web/img/no-image.png' - ) - ->fillResize(260, 260) - ->render(), - [ - 'class' => 'img-responsive-image1', - ] - ), +
+
+ image ? $product->image->getPath() : '@frontend/web/img/no-image.png' + ) + ->fillResize(260, 260) + ->render(), [ - 'product/view', - 'id' => $product->id, + 'class' => 'img-responsive-image1', ] - ); - ?> -
- -
-

- lang->title, - [ - 'product/view', - 'id' => $product->id, - ] - ); - ?> -

-

- variants[ 0 ]->price_old) { - echo Html::tag('del', $product->variants[ 0 ]->price_old . ' грн.'); - } - echo $product->variants[ 0 ]->price ? : 0 . ' грн.'; - ?>

-

- 'fa fa-shopping-cart', - ] - ) . \Yii::t('app', 'В корзину'), - '#', - [ 'class' => 'btn btn-template-main' ] - ); - ?> -

-
- - is('new')) { - ?> -
-
-
-
- is('akcia')) { - ?> -
-
-
-
- $product->id, + ] + ); ?> - -
- + +
+

+ lang->title, + [ + 'product/view', + 'id' => $product->id, + ] + ); + ?> +

+

+ variants[ 0 ]->price_old) { + echo Html::tag('del', $product->variants[ 0 ]->price_old . ' грн.'); + } + echo ( $product->variants[ 0 ]->price ? : 0 ) . ' грн.'; + ?>

+

+ variants[ 0 ]->stock && $product->variants[ 0 ]->price) { + echo Html::a( + Html::tag( + 'i', + '', + [ + 'class' => 'fa fa-shopping-cart', + ] + ) . \Yii::t('app', 'В корзину'), + '#', + [ + 'class' => 'btn btn-template-main add-to-basket', + 'data-id' => $product->variants[ 0 ]->id, + ] + ); + } else { + echo Html::a( + \Yii::t('app', 'Нет в наличии'), + '#', + [ + 'class' => 'btn btn-info disabled', + 'data-id' => $product->variants[ 0 ]->id, + ] + ); + } + ?> +

+
+ + is('new')) { + ?> +
+
+
+
+ is('akcia')) { + ?> +
+
+
+
+ + + +
+
diff --git a/frontend/views/site/login.php b/frontend/views/site/login.php new file mode 100644 index 0000000..26201e5 --- /dev/null +++ b/frontend/views/site/login.php @@ -0,0 +1,112 @@ +title = \Yii::t('app', 'Новый аккаунт / Регистрация'); + $this->params[ 'breadcrumbs' ][] = $this->title; +?> +
+
+ +
+
+
+

+ +

+

Html::a( + \Yii::t('app', 'напишите нам'), + [ + 'page/view', + 'id' => 17, + ] + ), + ] + ); ?>

+ +
+ + field($signupForm, 'username') + ->textInput(); + echo $formSignup->field($signupForm, 'email') + ->textInput(); + echo $formSignup->field($signupForm, 'password') + ->passwordInput(); + echo Html::tag( + 'div', + Html::submitButton( + Html::icon( + 'user-md', + [ + 'prefix' => 'fa fa-', + ] + ) . \Yii::t('app', 'Register'), + [ + 'class' => 'btn btn-template-main', + ] + ), + [ + 'class' => 'text-center', + ] + ); + $formSignup::end(); + ?> +
+
+ +
+
+

+ +

+ +
+ + field($loginForm, 'username') + ->textInput(); + echo $formLogin->field($loginForm, 'password') + ->passwordInput(); + echo $formLogin->field($loginForm, 'rememberMe') + ->checkbox(); + echo Html::tag( + 'div', + Html::submitButton( + Html::icon( + 'sign-in', + [ + 'prefix' => 'fa fa-', + ] + ) . \Yii::t('app', 'Login'), + [ + 'class' => 'btn btn-template-main', + ] + ), + [ + 'class' => 'text-center', + ] + ); + $formSignup::end(); + ?> +
+
+ +
+ + +
+ +
\ No newline at end of file diff --git a/frontend/views/site/requestPasswordResetToken.php b/frontend/views/site/requestPasswordResetToken.php new file mode 100644 index 0000000..371742e --- /dev/null +++ b/frontend/views/site/requestPasswordResetToken.php @@ -0,0 +1,33 @@ +title = 'Request password reset'; + $this->params[ 'breadcrumbs' ][] = $this->title; +?> +
+

title) ?>

+ +

Please fill out your email. A link to reset password will be sent there.

+ +
+
+ 'request-password-reset-form' ]); ?> + + field($model, 'email') + ->textInput([ 'autofocus' => true ]) ?> + +
+ 'btn btn-primary' ]) ?> +
+ + +
+
+
\ No newline at end of file diff --git a/frontend/views/site/resetPassword.php b/frontend/views/site/resetPassword.php new file mode 100644 index 0000000..56acace --- /dev/null +++ b/frontend/views/site/resetPassword.php @@ -0,0 +1,33 @@ +title = 'Reset password'; + $this->params[ 'breadcrumbs' ][] = $this->title; +?> +
+

title) ?>

+ +

Please choose your new password:

+ +
+
+ 'reset-password-form' ]); ?> + + field($model, 'password') + ->passwordInput([ 'autofocus' => true ]) ?> + +
+ 'btn btn-primary' ]) ?> +
+ + +
+
+
\ No newline at end of file diff --git a/frontend/web/css/style.css b/frontend/web/css/style.css index 7bdea96..15053ed 100755 --- a/frontend/web/css/style.css +++ b/frontend/web/css/style.css @@ -4495,25 +4495,28 @@ a.list-group-item.active > .badge, right: 15px; } -.radio-but{ +.radio-but { padding: 5px 0 5px 38px; position: relative; margin: 5px 0; } -.radio-but a:before{ - content:''; - position:absolute; - left:0; - top:0; + +.radio-but a:before { + content: ''; + position: absolute; + left: 0; + top: 0; width: 28px; - height:28px; + height: 28px; background: rgb(215, 220, 222); border-radius: 5px; } -.radio-but.checked a:before{ + +.radio-but.checked a:before { background: rgb(26, 188, 156); } -.radio-but.checked a:after{ + +.radio-but.checked a:after { content: ''; position: absolute; left: 0; @@ -4530,7 +4533,8 @@ a.list-group-item.active > .badge, font-size: 18px; padding-right: 20px; } -.reset-filters{ + +.reset-filters { padding: 5px 10px; font-size: 12px; line-height: 1.5; @@ -4539,8 +4543,100 @@ a.list-group-item.active > .badge, outline: none; margin-bottom: 20px; } -#cart .badge{ + +#cart .badge { position: absolute; top: 2px; right: 4px; +} + +.basket-container { + position: relative; +} + +.order-radio { + height: 10px; +} + +.loader-wrapper { + background: rgba(255, 255, 255, 0.7); + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 2000; +} + +.loader { + display: block; + position: relative; + left: 50%; + top: 50%; + width: 150px; + height: 150px; + margin: -75px 0 0 -75px; + border-radius: 50%; + border: 3px solid transparent; + border-top-color: #1980b3; + z-index: 2001; + + -webkit-animation: spin 2s linear infinite; + animation: spin 2s linear infinite; +} + +.loader:before { + content: ""; + position: absolute; + top: 5px; + left: 5px; + right: 5px; + bottom: 5px; + border-radius: 50%; + border: 3px solid transparent; + border-top-color: #3399cc; + + -webkit-animation: spin 3s linear infinite; + animation: spin 3s linear infinite; +} + +.loader:after { + content: ""; + position: absolute; + top: 15px; + left: 15px; + right: 15px; + bottom: 15px; + border-radius: 50%; + border: 3px solid transparent; + border-top-color: #70b7da; + + -webkit-animation: spin 1.5s linear infinite; + animation: spin 1.5s linear infinite; +} + +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + -ms-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + -ms-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } } \ No newline at end of file diff --git a/frontend/web/js/script.js b/frontend/web/js/script.js index ed766d7..01842c6 100755 --- a/frontend/web/js/script.js +++ b/frontend/web/js/script.js @@ -1,6 +1,8 @@ $( function() { - + var basket = new ArtboxBasket({ + 'cartSelector': '#cart' + }); /** * Modal form submit code */ @@ -52,7 +54,7 @@ $( data: formData, success: function(data) { f.reset(); - form.replaceWith(data.alert) + form.replaceWith(data.alert); }, error: function() { @@ -103,5 +105,56 @@ $( } ); } + + $(document) + .on('click', '.add-to-basket', function(e) { + e.preventDefault(); + var id = $(this) + .data('id'); + basket.add(id, 1); + }); + + $(document) + .on('click', '.remove-product-cart', function(e) { + e.preventDefault(); + var id = $(this) + .parents('.product-row-basket') + .data('id'); + showLoader('#basket'); + var xhr = basket.remove(id); + xhr.done(function() { + $.pjax.reload({ + container: '#basket', + fragment: '#basket', + timeout: 5000 + }); + }) + }); + + $(document) + .on('change', '.increase-product-basket', function(e) { + var id = $(this) + .parents('.product-row-basket') + .data('id'); + showLoader('#basket'); + var xhr = basket.set(id, $(this) + .val()); + xhr.done(function() { + $.pjax.reload({ + container: '#basket', + fragment: '#basket', + timeout: 5000 + }); + }); + }); + + $(document) + .on('click', 'li.disabled a', function(e) { + e.preventDefault(); + }); } -); \ No newline at end of file +); +function showLoader(container) { + $(container) + .prepend('
'); +} \ No newline at end of file -- libgit2 0.21.4