customer & review

This commit is contained in:
rahul shukla 2018-09-08 14:11:36 +05:30
commit 149c98ff03
73 changed files with 4136 additions and 470 deletions

View File

@ -0,0 +1,27 @@
<?php
namespace App\Criteria;
use Prettus\Repository\Contracts\CriteriaInterface;
use Prettus\Repository\Contracts\RepositoryInterface;
/**
* Class MyCriteria.
*
* @package namespace App\Criteria;
*/
class MyCriteria implements CriteriaInterface
{
/**
* Apply criteria in query repository
*
* @param string $model
* @param RepositoryInterface $repository
*
* @return mixed
*/
public function apply($model, RepositoryInterface $repository)
{
return $model;
}
}

View File

@ -0,0 +1,184 @@
<?php
namespace Webkul\Admin\DataGrids;
use Illuminate\View\View;
use Webkul\Ui\DataGrid\Facades\DataGrid;
/**
* Customer DataGrid
*
* @author Rahul Shukla <rahulshukla.symfony517@webkul.com> @rahul-webkul
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class CustomerDataGrid
{
/**
* The CustomerDataGrid
* implementation.
*
* @var CustomerDataGrid
*/
public function createCustomerDataGrid()
{
return DataGrid::make([
'name' => 'Customer',
'table' => 'customers',
'select' => 'id',
'perpage' => 10,
'aliased' => false, //use this with false as default and true in case of joins
'massoperations' =>[
[
'route' => route('admin.datagrid.delete'),
'method' => 'DELETE',
'label' => 'Delete',
'type' => 'button',
],
],
'actions' => [
[
'type' => 'Edit',
'route' => route('admin.datagrid.delete'),
'confirm_text' => 'Do you really want to do this?',
'icon' => 'icon pencil-lg-icon',
], [
'type' => 'Delete',
'route' => route('admin.datagrid.delete'),
'confirm_text' => 'Do you really want to do this?',
'icon' => 'icon trash-icon',
],
],
'join' => [
// [
// 'join' => 'leftjoin',
// 'table' => 'roles as r',
// 'primaryKey' => 'u.role_id',
// 'condition' => '=',
// 'secondaryKey' => 'r.id',
// ]
],
//use aliasing on secodary columns if join is performed
'columns' => [
[
'name' => 'id',
'alias' => 'customerId',
'type' => 'number',
'label' => 'ID',
'sortable' => true,
],
[
'name' => 'first_name',
'alias' => 'customerFirstName',
'type' => 'string',
'label' => 'Name',
'sortable' => true,
],
[
'name' => 'email',
'alias' => 'customerEmail',
'type' => 'string',
'label' => 'Email',
'sortable' => true,
],
[
'name' => 'phone',
'alias' => 'customerPhone',
'type' => 'number',
'label' => 'Phone',
'sortable' => true,
],
[
'name' => 'customer_group_id',
'alias' => 'customerGroupId',
'type' => 'number',
'label' => 'Customer Group',
'sortable' => true,
],
],
//don't use aliasing in case of filters
'filterable' => [
[
'name' => 'id',
'alias' => 'customerId',
'type' => 'number',
'label' => 'ID',
],
[
'name' => 'first_name',
'alias' => 'customerFirstName',
'type' => 'string',
'label' => 'Name',
],
[
'name' => 'phone',
'alias' => 'customerPhone',
'type' => 'number',
'label' => 'Phone',
],
[
'name' => 'email',
'alias' => 'customerEmail',
'type' => 'string',
'label' => 'Comment',
],
[
'name' => 'customer_group_id',
'alias' => 'customerGroupId',
'type' => 'number',
'label' => 'Status',
],
],
//don't use aliasing in case of searchables
'searchable' => [
[
'column' => 'first_name',
'type' => 'string',
'label' => 'Title',
],
[
'column' => 'email',
'type' => 'string',
'label' => 'Rating',
],
],
//list of viable operators that will be used
'operators' => [
'eq' => "=",
'lt' => "<",
'gt' => ">",
'lte' => "<=",
'gte' => ">=",
'neqs' => "<>",
'neqn' => "!=",
'like' => "like",
'nlike' => "not like",
],
// 'css' => []
]);
}
public function render()
{
return $this->createCustomerDataGrid()->render();
}
}

View File

@ -0,0 +1,183 @@
<?php
namespace Webkul\Admin\DataGrids;
use Illuminate\View\View;
use Webkul\Ui\DataGrid\Facades\DataGrid;
/**
* Review DataGrid
*
* @author Rahul Shukla <rahulshukla.symfony517@webkul.com> @rahul-webkul
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class CustomerReviewDataGrid
{
/**
* The CustomerReviewDataGrid
* implementation.
*
* @var ReviewsDataGrid
* for Reviews
*/
public function createCustomerReviewDataGrid()
{
return DataGrid::make([
'name' => 'Review',
'table' => 'product_reviews',
'select' => 'id',
'perpage' => 10,
'aliased' => false, //use this with false as default and true in case of joins
'massoperations' =>[
[
'route' => route('admin.datagrid.delete'),
'method' => 'DELETE',
'label' => 'Delete',
'type' => 'button',
],
],
'actions' => [
[
'type' => 'Edit',
'route' => route('admin.datagrid.delete'),
'confirm_text' => 'Do you really want to do this?',
'icon' => 'icon pencil-lg-icon',
], [
'type' => 'Delete',
'route' => route('admin.datagrid.delete'),
'confirm_text' => 'Do you really want to do this?',
'icon' => 'icon trash-icon',
],
],
'join' => [
// [
// 'join' => 'leftjoin',
// 'table' => 'roles as r',
// 'primaryKey' => 'u.role_id',
// 'condition' => '=',
// 'secondaryKey' => 'r.id',
// ]
],
//use aliasing on secodary columns if join is performed
'columns' => [
[
'name' => 'id',
'alias' => 'reviewId',
'type' => 'number',
'label' => 'ID',
'sortable' => true,
],
[
'name' => 'title',
'alias' => 'titleName',
'type' => 'string',
'label' => 'Title',
'sortable' => true,
],
[
'name' => 'rating',
'alias' => 'productRating',
'type' => 'number',
'label' => 'Rating',
'sortable' => true,
],
[
'name' => 'comment',
'alias' => 'productComment',
'type' => 'string',
'label' => 'Comment',
'sortable' => true,
],
[
'name' => 'status',
'alias' => 'countryStatus',
'type' => 'number',
'label' => 'Status',
'sortable' => true,
],
],
//don't use aliasing in case of filters
'filterable' => [
[
'name' => 'id',
'alias' => 'countryId',
'type' => 'number',
'label' => 'ID',
],
[
'name' => 'title',
'alias' => 'titleName',
'type' => 'string',
'label' => 'Title',
],
[
'name' => 'rating',
'alias' => 'productRating',
'type' => 'number',
'label' => 'Rating',
],
[
'name' => 'comment',
'alias' => 'productComment',
'type' => 'string',
'label' => 'Comment',
],
[
'name' => 'status',
'alias' => 'countryStatus',
'type' => 'number',
'label' => 'Code',
],
],
//don't use aliasing in case of searchables
'searchable' => [
[
'column' => 'title',
'type' => 'string',
'label' => 'Title',
],
[
'column' => 'rating',
'type' => 'number',
'label' => 'Rating',
],
],
//list of viable operators that will be used
'operators' => [
'eq' => "=",
'lt' => "<",
'gt' => ">",
'lte' => "<=",
'gte' => ">=",
'neqs' => "<>",
'neqn' => "!=",
'like' => "like",
'nlike' => "not like",
],
// 'css' => []
]);
}
public function render()
{
return $this->createCustomerReviewDataGrid()->render();
}
}

View File

@ -36,12 +36,44 @@ Route::group(['middleware' => ['web']], function () {
'redirect' => 'admin.session.create'
])->name('admin.session.destroy');
//orders page
// Dashboard Route
Route::get('/dashboard', 'Webkul\Admin\Http\Controllers\DashboardController@index')->name('admin.dashboard.index');
Route::get('dashboard', 'Webkul\Admin\Http\Controllers\DashboardController@index')->name('admin.dashboard.index');
//Customers Management Routes
Route::get('customer', 'Webkul\Core\Http\Controllers\CustomerController@index')->defaults('_config', [
'view' => 'admin::customers.index'
])->name('admin.customer.index');
Route::get('customer/orders', 'Webkul\Core\Http\Controllers\CustomerController@index')->defaults('_config',[
'view' => 'admin::customers.orders.index'
])->name('admin.customer.orders.index');
Route::get('customer/reviews', 'Webkul\Shop\Http\Controllers\ReviewController@index')->defaults('_config',[
'view' => 'admin::customers.review.index'
])->name('admin.customer.review.index');
Route::get('customer/reviews/edit/{id}', 'Webkul\Shop\Http\Controllers\ReviewController@edit')->defaults('_config',[
'view' => 'admin::customers.review.edit'
])->name('admin.customer.review.edit');
Route::put('customer/reviews/edit/{id}', 'Webkul\Shop\Http\Controllers\ReviewController@update')->defaults('_config', [
'redirect' => 'admin.customer.review.index'
])->name('admin.customer.review.update');
Route::get('customer/edit/{id}', 'Webkul\Core\Http\Controllers\CustomerController@edit')->defaults('_config',[
'view' => 'admin::customers.edit'
])->name('admin.customer.edit');
Route::put('customer/reviews/edit/{id}', 'Webkul\Core\Http\Controllers\CustomerController@update')->defaults('_config', [
'redirect' => 'admin.customer.index'
])->name('admin.customer.update');
// dummy number i.e-1 is used for creating view only
Route::get('customer/orders/1', 'Webkul\User\Http\Controllers\UserController@index')->defaults('_config', [
'view' => 'admin::customers.orders.order'
])->name('admin.customer.orders.order');
// Catalog Routes
Route::prefix('catalog')->group(function () {

View File

@ -52,6 +52,18 @@ class EventServiceProvider extends ServiceProvider
$menu->add('catalog.families', 'Families', 'admin.catalog.families.index', 4);
$menu->add('customers', 'Customers', 'admin.customer.index', 5, 'customer-icon');
$menu->add('customers.customers', 'Customers', 'admin.customer.index', 1, '');
$menu->add('customers.orders', 'Orders', 'admin.customer.orders.index', 2, '');
$menu->add('customers.reviews', 'Review', 'admin.customer.review.index', 3, '');
// $menu->add('customers.blocked_customer', 'Blocked Customers', 'admin.account.edit', 2, '');
// $menu->add('customers.allowed_customer', 'Allowed Customers', 'admin.account.edit', 4, '');
$menu->add('configuration', 'Configure', 'admin.account.edit', 6, 'configuration-icon');
$menu->add('configuration.account', 'My Account', 'admin.account.edit', 1);

View File

@ -274,3 +274,28 @@ body {
}
// admin dashboard css ends here
// customer oder css for admin start here
.order-place-detail {
.order-account-information {
margin-left: 10px;
}
.address {
margin-left: 10px;
}
.payment-shipping{
margin-left: 10px;
}
.order-products{
margin-left: 10px;
}
}
// customer oder css for admin end here

View File

@ -133,7 +133,8 @@ return [
'value_per_channel' => 'Value Per Channel',
'is_filterable' => 'Use in Layered Navigation',
'is_configurable' => 'Use To Create Configurable Product',
'admin_name' => 'Admin Name'
'admin_name' => 'Admin Name',
'is_visible_on_front' => 'Visible on Product View Page on Front-end'
],
'families' => [
'families' => 'Families',
@ -264,5 +265,24 @@ return [
'content' => 'Content',
'channels' => 'Channel'
],
],
'customers' => [
'customers' => [
'title' => 'Customers',
'first_name' => 'First Name',
'last_name' => 'Last Name',
'gender' => 'Gender',
'email' => 'Email',
'date_of_birth' => 'Date of Birth',
'phone' => 'Phone',
'customer_group' => 'Customer Group'
],
'reviews' => [
'title' => 'Title',
'name' => 'Reviews',
'rating' => 'Rating',
'status' => 'Status',
'comment' => 'Comment'
]
]
];

View File

@ -154,6 +154,14 @@
<option value="1">{{ __('admin::app.catalog.attributes.yes') }}</option>
</select>
</div>
<div class="control-group">
<label for="is_visible_on_front">{{ __('admin::app.catalog.attributes.is_visible_on_front') }}</label>
<select class="control" id="is_visible_on_front" name="is_visible_on_front">
<option value="0">{{ __('admin::app.catalog.attributes.no') }}</option>
<option value="1">{{ __('admin::app.catalog.attributes.yes') }}</option>
</select>
</div>
</div>
</accordian>

View File

@ -210,6 +210,18 @@
</option>
</select>
</div>
<div class="control-group">
<label for="is_visible_on_front">{{ __('admin::app.catalog.attributes.is_visible_on_front') }}</label>
<select class="control" id="is_visible_on_front" name="is_visible_on_front">
<option value="0" {{ $attribute->is_visible_on_front ? '' : 'selected' }}>
{{ __('admin::app.catalog.attributes.no') }}
</option>
<option value="1" {{ $attribute->is_visible_on_front ? 'selected' : '' }}>
{{ __('admin::app.catalog.attributes.yes') }}
</option>
</select>
</div>
</div>
</accordian>

View File

@ -19,7 +19,7 @@
<div class="control-group">
<select class="control" id="channel-switcher" name="channel">
@foreach(core()->getAllChannels() as $channelModel)
<option value="{{ $channelModel->code }}" {{ ($channelModel->code) == $channel ? 'selected' : '' }}>
{{ $channelModel->name }}
</option>
@ -31,7 +31,7 @@
<div class="control-group">
<select class="control" id="locale-switcher" name="locale">
@foreach(core()->getAllLocales() as $localeModel)
<option value="{{ $localeModel->code }}" {{ ($localeModel->code) == $locale ? 'selected' : '' }}>
{{ $localeModel->name }}
</option>
@ -61,8 +61,8 @@
@foreach($attributeGroup->custom_attributes as $attribute)
@if(!$product->super_attributes->contains($attribute))
<?php
<?php
$validations = [];
$disabled = false;
if($product->type == 'configurable' && in_array($attribute->code, ['price', 'cost', 'special_price', 'special_price_from', 'special_price_to', 'width', 'height', 'depth', 'weight'])) {
@ -79,7 +79,7 @@
}
$validations = implode('|', array_filter($validations));
?>
?>
@if(view()->exists($typeView = 'admin::catalog.products.field-types.' . $attribute->type))
@ -97,7 +97,7 @@
array_push($channel_locale, $locale);
}
?>
@if(count($channel_locale))
<span class="locale">[{{ implode(' - ', $channel_locale) }}]</span>
@endif
@ -111,7 +111,7 @@
@endif
@endif
@endforeach
</div>
@ -120,11 +120,11 @@
@endforeach
@if ($form_accordians)
@foreach ($form_accordians->items as $accordian)
@include ($accordian['view'])
@endforeach
@endif

View File

@ -0,0 +1,81 @@
@extends('admin::layouts.content')
@section('content')
<div class="content">
<form method="POST" action="{{ route('admin.customer.update', $customer->id) }}">
<div class="page-header">
<div class="page-title">
<h1>
{{ __('admin::app.customers.customers.title') }}
</h1>
</div>
<div class="page-action">
<button type="submit" class="btn btn-lg btn-primary">
{{ __('admin::app.account.save-btn-title') }}
</button>
</div>
</div>
<div class="page-content">
<div class="form-container">
@csrf()
<input name="_method" type="hidden" value="PUT">
<accordian :title="'{{ __('admin::app.account.general') }}'" :active="true">
<div slot="body">
<div class="control-group">
<label for="name" > {{ __('admin::app.customers.customers.first_name') }}</label>
<input type="text" class="control" name="first_name" value="{{$customer->first_name}}"/>
</div>
<div class="control-group">
<label for="name" > {{ __('admin::app.customers.customers.last_name') }}</label>
<input type="text" class="control" name="last_name" value="{{$customer->last_name}}"/>
</div>
<div class="control-group">
<label for="name" > {{ __('admin::app.customers.customers.email') }}</label>
<input type="text" class="control" name="email" value="{{$customer->email}}"/>
</div>
<div class="control-group">
<label for="email">{{ __('admin::app.customers.customers.gender') }}</label>
<select name="gender" class="control" value="{{ $customer->gender }}" v-validate="'required'">
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
</div>
<div class="control-group">
<label for="dob">{{ __('admin::app.customers.customers.date_of_birth') }}</label>
<input type="date" class="control" name="date_of_birth" value="{{ $customer->date_of_birth }}" v-validate="'required'">
</div>
<div class="control-group">
<label for="phone">{{ __('admin::app.customers.customers.phone') }}</label>
<input type="text" class="control" name="phone" value="{{ $customer->phone }}" v-validate="'required'">
</div>
<div class="control-group">
<label for="name" >{{ __('admin::app.customers.customers.customer_group') }}</label>
<select class="control" name="customer_group_id">
<option value="1"> 1 </option>
<option value="2"> 2 </option>
<option value="3"> 3 </option>
<option value="4"> 4 </option>
</select>
</div>
</div>
</accordian>
</div>
</div>
</form>
</div>
@stop

View File

@ -0,0 +1,28 @@
@extends('admin::layouts.content')
@section('page_title')
@stop
@section('content')
<div class="content">
<div class="page-header">
<div class="page-title">
<h1>{{ __('admin::app.customers.customers.title') }}</h1>
</div>
<div class="page-action">
<a href="{{ route('admin.users.create') }}" class="btn btn-lg btn-primary">
{{ __('Add Customer') }}
</a>
</div>
</div>
<div class="page-content">
@inject('customer','Webkul\Admin\DataGrids\CustomerDataGrid')
{!! $customer->render() !!}
</div>
</div>
@stop

View File

@ -0,0 +1,25 @@
@extends('admin::layouts.content')
@section('page_title')
@stop
@section('content')
<div class="content">
<div class="page-header">
<div class="page-title">
<h1>Customers</h1>
</div>
<div class="page-action">
<a href="{{ route('admin.users.create') }}" class="btn btn-lg btn-primary">
{{ __('Add Customer') }}
</a>
</div>
</div>
<div class="page-content">
</div>
</div>
@stop

View File

@ -0,0 +1,353 @@
@extends('admin::layouts.master')
@section('content-wrapper')
<div class="order-place-detail">
<div class="order-account-information">
<accordian :title="'Order and Account'" :active="true">
<div slot="body">
<div class="order-information">
<div class="order-info">
<span>Order Information <span >
<span class="edit">
Edit
</span>
</div>
<div class="horizotal-rule"> </div>
<div class="order-account">
<div class="left-content">
<span>
Order Date
</span>
</div>
<div class="right-content">
<span>
August 4,2018,9:05:36:AM
</span>
</div>
</div>
<div class="order-account">
<div class="left-content">
<span>
Order Status
</span>
</div>
<div class="right-content">
<span>
Pending
</span>
</div>
</div>
<div class="order-account">
<div class="left-content">
<span>
Channel
</span>
</div>
<div class="right-content">
<span>
Web Store-en_GB
</span>
</div>
</div>
</div>
<div class="account-information">
<div class="account-info">
<span>Account Information <span >
<span class="edit">
Edit
</span>
</div>
<div class="horizotal-rule"> </div>
<div class="order-account">
<div class="left-content">
<span >
Customer Name
</span>
</div>
<div class="right-content">
<span class="name">
Lee Stoike
</span>
</div>
</div>
<div class="order-account">
<div class="left-content">
<span>
Email
</span>
</div>
<div class="right-content">
<span>
lee.stoike@examplemail.com
</span>
</div>
</div>
<div class="order-account">
<div class="left-content">
<span>
Contact Number
</span>
</div>
<div class="right-content">
<span>
9876543210
</span>
</div>
</div>
</div>
</div>
</accordian>
</div>
<div class="address">
<accordian :title="'Address'" :active="true">
<div slot="body">
<div class="address-information">
<div class="address-name">
<span> Shipping Address <span >
<span class="edit">
Edit
</span>
</div>
<div class="horizotal-rule"> </div>
<div class="address-detail">
<span> 0933 Crossing Suite 12B </span>
<span> Dallas , Texas <span>
<span> United States </span>
<span> 75001 </span>
</div>
</div>
<div class="address-information">
<div class="address-name">
<span> Billing Address <span >
<span class="edit">
Edit
</span>
</div>
<div class="horizotal-rule"> </div>
<div class="address-detail">
<span> 0933 Crossing Suite 12B </span>
<span> Dallas , Texas <span>
<span> United States </span>
<span> 75001 </span>
</div>
</div>
</div>
</accordian>
</div>
<div class="payment-shipping">
<accordian :title="'Payment and Shipping'" :active="true">
<div slot="body">
<div class="payment-information">
<div class="title">
<span>Payment Information <span >
</div>
<div class="horizotal-rule"> </div>
<div class="payment-info">
<div class="left-content">
<span>
Payment Method
</span>
</div>
<div class="right-content">
<span>
Bank Wire Transfer
</span>
</div>
</div>
<div class="payment-info">
<div class="left-content">
<span>
Currency
</span>
</div>
<div class="right-content">
<span>
US Dollar
</span>
</div>
</div>
</div>
<div class="payment-information">
<div class="title">
<span> Shipping Information <span >
</div>
<div class="horizotal-rule"> </div>
<div class="payment-info">
<div class="left-content">
<span>
Shipping Method
</span>
</div>
<div class="right-content">
<span>
Flat Rate-Fixed-$10.00
</span>
</div>
</div>
<div class="payment-info">
<div class="left-content">
<span>
Expected Delivery
</span>
</div>
<div class="right-content">
<span>
3 Days
</span>
</div>
</div>
</div>
</div>
</accordian>
</div>
<div class="order-products">
<accordian :title="'Products Ordered'" :active="true">
<div slot="body">
<div class="table">
<table>
<thead>
<tr>
<th>SKU</th>
<th>Product Name</th>
<th>Item Status</th>
<th>Price</th>
<th>Qty</th>
<th>Row total</th>
</tr>
</thead>
<tbody>
<tr>
<td>PROD124</td>
<td>Apple iPhone 7- White-32GB</td>
<td>Packed (2)</td>
<td>$350.00</td>
<td>2</td>
<td>$700.00</td>
</tr>
<tr>
<td>PROD128</td>
<td>Blue Linen T-Shirt for Men- Small- Red</td>
<td>Shipped (2)</td>
<td>$45.00</td>
<td>2</td>
<td>$35.00</td>
</tr>
</tbody>
</table>
</div>
<div class="total">
<div class="calculate">
<div class="sub-total">
<span class="left">
Subtotal
</span>
<span class="middle">
-
</span>
<span class="right">
$805.00
</span>
</div>
<div class="ship-handle">
<span class="left">
Shipping & handling
</span>
<span class="middle">
-
</span>
<span class="right">
$5.00
</span>
</div>
<div class="discount">
<span class="left">
Discounts
</span>
<span class="middle">
-
</span>
<span class="right">
$15.00
</span>
</div>
<div class="grand-total">
<span class="left">
Grand Total
</span>
<span class="middle">
-
</span>
<span class="right">
$15.00
</span>
</div>
<div class="due">
<span class="left">
Total Due
</span>
<span class="middle">
-
</span>
<span class="right">
$15.00
</span>
</div>
</div>
</div>
</div>
</accordian>
</div>
<div>
@stop

View File

@ -0,0 +1,69 @@
@extends('admin::layouts.content')
@section('content')
<div class="content">
<form method="POST" action="{{ route('admin.customer.review.update', $review->id) }}">
<div class="page-header">
<div class="page-title">
<h1>
{{ __('admin::app.customers.reviews.name') }}
</h1>
</div>
<div class="page-action">
<button type="submit" class="btn btn-lg btn-primary">
{{ __('admin::app.account.save-btn-title') }}
</button>
</div>
</div>
<div class="page-content">
<div class="form-container">
@csrf()
<input name="_method" type="hidden" value="PUT">
<accordian :title="'{{ __('admin::app.account.general') }}'" :active="true">
<div slot="body">
<div class="control-group">
<label for="name" > {{ __('admin::app.customers.reviews.title') }}</label>
<input type="text" class="control" id="name" name="name" value="{{$review->title}}" disabled/>
</div>
<div class="control-group">
<label for="name" >{{ __('admin::app.customers.reviews.rating') }}</label>
@for($i = 1; $i <= $review->rating ; $i++)
<span class="stars">
<span class="icon star-icon"></span>
</span>
@endfor
</div>
<div class="control-group">
<label for="name" >{{ __('admin::app.customers.reviews.status') }}</label>
<select class="control" name="status">
<option value="1">
1
</option>
<option value="2">
2
</option>
</select>
</div>
<div class="control-group">
<label for="name" >{{ __('admin::app.customers.reviews.comment') }}</label>
<textarea class="control" disabled> {{$review->comment}}</textarea>
</div>
</div>
</accordian>
</div>
</div>
</form>
</div>
@stop

View File

@ -0,0 +1,27 @@
@extends('admin::layouts.content')
@section('page_title')
@stop
@section('content')
<div class="content">
<div class="page-header">
<div class="page-title">
<h1>{{ __('admin::app.customers.reviews.name') }}</h1>
</div>
<div class="page-action">
{{-- <a href="{{ route('admin.users.create') }}" class="btn btn-lg btn-primary">
{{ __('Add Customer') }}
</a> --}}
</div>
</div>
<div class="page-content">
@inject('review','Webkul\Admin\DataGrids\CustomerReviewDataGrid')
{!! $review->render() !!}
</div>
</div>
@stop

View File

@ -1,6 +1,12 @@
@extends('admin::layouts.content')
@section('page_title')
@stop
@section('content')
<div class="content">
<div class="page-header">
<div class="page-title">

View File

@ -27,6 +27,7 @@ class CreateAttributesTable extends Migration
$table->boolean('is_filterable')->default(0);
$table->boolean('is_configurable')->default(0);
$table->boolean('is_user_defined')->default(1);
$table->boolean('is_visible_on_front')->default(0);
$table->timestamps();
});
}

View File

@ -14,9 +14,9 @@ class AttributeTableSeeder extends Seeder
[
'code' => 'sku',
'admin_name' => 'SKU',
'en' => [
'name' => 'SKU'
],
// 'en' => [
// 'name' => 'SKU'
// ],
'type' => 'text',
'position' => 1,
'is_unique' => 1,
@ -29,9 +29,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'name',
'admin_name' => 'Name',
'en' => [
'name' => 'Name'
],
// 'en' => [
// 'name' => 'Name'
// ],
'type' => 'text',
'position' => 2,
'is_required' => 1,
@ -43,9 +43,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'url_key',
'admin_name' => 'URL Key',
'en' => [
'name' => 'URL Key'
],
// 'en' => [
// 'name' => 'URL Key'
// ],
'type' => 'text',
'position' => 3,
'is_unique' => 1,
@ -58,9 +58,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'new_from',
'admin_name' => 'New From',
'en' => [
'name' => 'New From'
],
// 'en' => [
// 'name' => 'New From'
// ],
'type' => 'datetime',
'position' => 4,
'is_required' => 0,
@ -72,9 +72,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'new_to',
'admin_name' => 'New To',
'en' => [
'name' => 'New To'
],
// 'en' => [
// 'name' => 'New To'
// ],
'type' => 'datetime',
'position' => 5,
'is_required' => 0,
@ -86,9 +86,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'visible_individually',
'admin_name' => 'Visible Individually',
'en' => [
'name' => 'Visible Individually'
],
// 'en' => [
// 'name' => 'Visible Individually'
// ],
'type' => 'boolean',
'position' => 6,
'is_required' => 1,
@ -100,9 +100,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'status',
'admin_name' => 'Status',
'en' => [
'name' => 'Status'
],
// 'en' => [
// 'name' => 'Status'
// ],
'type' => 'boolean',
'position' => 7,
'is_required' => 1,
@ -114,9 +114,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'short_description',
'admin_name' => 'Short Description',
'en' => [
'name' => 'Short Description'
],
// 'en' => [
// 'name' => 'Short Description'
// ],
'type' => 'textarea',
'position' => 8,
'is_required' => 1,
@ -128,9 +128,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'description',
'admin_name' => 'Description',
'en' => [
'name' => 'Description'
],
// 'en' => [
// 'name' => 'Description'
// ],
'type' => 'textarea',
'position' => 9,
'is_required' => 1,
@ -142,9 +142,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'price',
'admin_name' => 'Price',
'en' => [
'name' => 'Price'
],
// 'en' => [
// 'name' => 'Price'
// ],
'type' => 'price',
'position' => 10,
'is_required' => 1,
@ -156,9 +156,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'cost',
'admin_name' => 'Cost',
'en' => [
'name' => 'Cost'
],
// 'en' => [
// 'name' => 'Cost'
// ],
'type' => 'price',
'position' => 11,
'is_required' => 0,
@ -170,9 +170,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'special_price',
'admin_name' => 'Special Price',
'en' => [
'name' => 'Special Price'
],
// 'en' => [
// 'name' => 'Special Price'
// ],
'type' => 'price',
'position' => 12,
'is_required' => 0,
@ -184,9 +184,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'special_price_from',
'admin_name' => 'Special Price From',
'en' => [
'name' => 'Special Price From'
],
// 'en' => [
// 'name' => 'Special Price From'
// ],
'type' => 'date',
'position' => 13,
'is_required' => 0,
@ -198,9 +198,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'special_price_to',
'admin_name' => 'Special Price To',
'en' => [
'name' => 'Special Price To'
],
// 'en' => [
// 'name' => 'Special Price To'
// ],
'type' => 'date',
'position' => 14,
'is_required' => 0,
@ -212,9 +212,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'meta_title',
'admin_name' => 'Meta Title',
'en' => [
'name' => 'Meta Description'
],
// 'en' => [
// 'name' => 'Meta Description'
// ],
'type' => 'textarea',
'position' => 15,
'is_required' => 0,
@ -226,9 +226,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'meta_keywords',
'admin_name' => 'Meta Keywords',
'en' => [
'name' => 'Meta Keywords'
],
// 'en' => [
// 'name' => 'Meta Keywords'
// ],
'type' => 'textarea',
'position' => 16,
'is_required' => 0,
@ -240,9 +240,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'meta_description',
'admin_name' => 'Meta Description',
'en' => [
'name' => 'Meta Description'
],
// 'en' => [
// 'name' => 'Meta Description'
// ],
'type' => 'textarea',
'position' => 17,
'is_required' => 0,
@ -254,9 +254,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'width',
'admin_name' => 'Width',
'en' => [
'name' => 'Width'
],
// 'en' => [
// 'name' => 'Width'
// ],
'type' => 'text',
'validation' => 'numeric',
'position' => 18,
@ -269,9 +269,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'height',
'admin_name' => 'Height',
'en' => [
'name' => 'Height'
],
// 'en' => [
// 'name' => 'Height'
// ],
'type' => 'text',
'validation' => 'numeric',
'position' => 19,
@ -284,9 +284,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'depth',
'admin_name' => 'Depth',
'en' => [
'name' => 'Depth'
],
// 'en' => [
// 'name' => 'Depth'
// ],
'type' => 'text',
'validation' => 'numeric',
'position' => 20,
@ -299,9 +299,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'weight',
'admin_name' => 'Weight',
'en' => [
'name' => 'Weight'
],
// 'en' => [
// 'name' => 'Weight'
// ],
'type' => 'text',
'validation' => 'numeric',
'position' => 21,
@ -314,9 +314,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'color',
'admin_name' => 'Color',
'en' => [
'name' => 'Color'
],
// 'en' => [
// 'name' => 'Color'
// ],
'type' => 'select',
'position' => 22,
'is_required' => 0,
@ -356,9 +356,9 @@ class AttributeTableSeeder extends Seeder
], [
'code' => 'size',
'admin_name' => 'Size',
'en' => [
'name' => 'Size'
],
// 'en' => [
// 'name' => 'Size'
// ],
'type' => 'select',
'position' => 23,
'is_required' => 0,

View File

@ -10,7 +10,7 @@ class Attribute extends TranslatableModel
{
public $translatedAttributes = ['name'];
protected $fillable = ['code', 'admin_name', 'type', 'position', 'is_required', 'is_unique', 'value_per_locale', 'value_per_channel', 'is_filterable', 'is_configurable'];
protected $fillable = ['code', 'admin_name', 'type', 'position', 'is_required', 'is_unique', 'value_per_locale', 'value_per_channel', 'is_filterable', 'is_configurable', 'is_visible_on_front'];
protected $with = ['options'];
@ -22,14 +22,6 @@ class Attribute extends TranslatableModel
return $this->hasMany(AttributeOption::class);
}
/**
* Get the options.
*/
public function filter_attributes()
{
}
/**
* Scope a query to only include popular users.
*

View File

@ -2,6 +2,7 @@
namespace Webkul\Core;
use Carbon\Carbon;
use Webkul\Core\Models\Channel as ChannelModel;
use Webkul\Core\Models\Locale as LocaleModel;
use Webkul\Core\Models\Currency as CurrencyModel;
@ -14,7 +15,12 @@ class Core
* @return Collection
*/
public function getAllChannels() {
return ChannelModel::all();
static $channels;
if($channels)
return $channels;
return $channels = ChannelModel::all();
}
/**
@ -23,7 +29,12 @@ class Core
* @return mixed
*/
public function getCurrentChannel() {
return ChannelModel::first();
static $channel;
if($channel)
return $channel;
return $channel = ChannelModel::first();
}
/**
@ -32,7 +43,12 @@ class Core
* @return string
*/
public function getCurrentChannelCode() {
return ($channel = $this->getCurrentChannel()) ? $channel->code : '';
static $channelCode;
if($channelCode)
return $channelCode;
return ($channel = $this->getCurrentChannel()) ? $channelCode = $channel->code : '';
}
/**
@ -41,7 +57,12 @@ class Core
* @return Collection
*/
public function getAllLocales() {
return LocaleModel::all();
static $locales;
if($locales)
return $locales;
return $locales = LocaleModel::all();
}
/**
@ -51,7 +72,12 @@ class Core
*/
public function getAllCurrencies()
{
return CurrencyModel::all();
static $currencies;
if($currencies)
return $currencies;
return $currencies = CurrencyModel::all();
}
/**
@ -61,9 +87,12 @@ class Core
*/
public function getCurrentCurrency()
{
$currency = CurrencyModel::first();
static $currency;
return $currency;
if($currency)
return $currency;
return $currency = CurrencyModel::first();
}
/**
@ -73,7 +102,12 @@ class Core
*/
public function getCurrentCurrencyCode()
{
return ($currency = $this->getCurrentCurrency()) ? $currency->code : '';
static $currencyCode;
if($currencyCode)
return $currencyCode;
return ($currency = $this->getCurrentCurrency()) ? $currencyCode = $currency->code : '';
}
/**
@ -83,7 +117,12 @@ class Core
*/
public function getCurrentCurrencySymbol()
{
return $this->getCurrentCurrency()->symbol;
static $currencySymbol;
if($currencySymbol)
return $currencySymbol;
return $currencySymbol = $this->getCurrentCurrency()->symbol;
}
/**
@ -99,7 +138,9 @@ class Core
$channel = $this->getCurrentChannel();
$currencyCode = $channel->base_currency->code;
$currencyCode = $channel->base_currency;
// $currencyCode = $channel->base_currency->code;
return currency($price, $currencyCode);
}
@ -171,4 +212,25 @@ class Core
}
// $timezonelist = \DateTimeZone::listIdentifiers(\DateTimeZone::ALL);
/**
* Format date using current channel.
*
* @param date|null $date
* @param string $format
* @return string
*/
public function formatDate($date = null, $format = 'd-m-Y H:i:s')
{
$channel = $this->getCurrentChannel();
if (is_null($date)) {
$date = Carbon::now();
}
$date->setTimezone($channel->timezone);
return $date->format($format);
}
}

View File

@ -0,0 +1,75 @@
<?php
namespace Webkul\Core\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Routing\Controller;
use Webkul\Customer\Models\Customer;
/**
* Customer controlller for the customer
* to show customer data on admin login
*
* @author Rahul Shukla <rahulshukla.symfony517@webkul.com>
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class CustomerController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
protected $_config;
public function __construct()
{
$this->_config = request('_config');
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
return view($this->_config['view']);
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
$customer = Customer::find($id);
dd($customer->customerGroup->group_name);
return view($this->_config['view'],compact('customer'));
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
$customer = Customer::find($id);
$customer->update(request()->all(), [$id]);
session()->flash('success', 'Customer updated successfully.');
return redirect()->route($this->_config['redirect']);
}
}

View File

@ -0,0 +1,81 @@
<?php
namespace Webkul\Core\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Webkul\Product\Repositories\ProductRepository as Product;
use Webkul\Product\Repositories\ProductReviewRepository as ProductReview;
/**
* Review controller
*
* @author Rahul Shukla <rahulshukla.symfony517@webkul.com>
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class ReviewController extends Controller
{
/**
* Contains route related configuration
*
* @var array
*/
protected $_config;
/**
* ProductRepository object
*
* @var array
*/
protected $product;
/**
* ProductReviewRepository object
*
* @var array
*/
protected $productReview;
/**
* Create a new controller instance.
*
* @param Webkul\Product\Repositories\ProductRepository $product
* @param Webkul\Product\Repositories\ProductReviewRepository $productReview
* @return void
*/
public function __construct(Product $product, ProductReview $productReview)
{
$this->product = $product;
$this->productReview = $productReview;
$this->_config = request('_config');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request , $id)
{
$this->validate(request(), [
'comment' => 'required',
]);
$input=$request->all();
$input['product_id']=$id;
$input['customer_id']=1;
$this->productReview->create($input);
session()->flash('success', 'Review submitted successfully.');
return redirect()->route($this->_config['redirect']);
}
}

View File

@ -13,7 +13,7 @@
{
$results = [];
while (list($key, $values) = each($input)) {
foreach ($input as $key => $values) {
if (empty($values)) {
continue;
}
@ -41,7 +41,7 @@
$results = array_merge($results, $append);
}
}
return $results;
}
}

View File

@ -27,6 +27,7 @@ class CustomerController extends Controller
public function __construct()
{
$this->middleware('customer');
$this->_config = request('_config');
}

View File

@ -4,6 +4,7 @@ namespace Webkul\Customer\Models;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Webkul\Customer\Models\CustomersGroups;
// use Webkul\User\Notifications\AdminResetPassword;
@ -15,5 +16,27 @@ class Customer extends Authenticatable
use Notifiable;
protected $table = 'customers';
protected $fillable = ['first_name', 'last_name', 'gender', 'date_of_birth','phone','email','customer_group_id','subscribed_to_news_letter'];
protected $hidden = ['password','remember_token'];
protected $with = ['customerGroup'];
/**
* Get the customer full name.
*/
public function getNameAttribute() {
return ucfirst($this->first_name) . ' ' . ucfirst($this->last_name);
}
/**
* Get the customer group that owns the customer.
*/
public function customerGroup()
{
return $this->belongsTo(CustomersGroups::class);
}
}

View File

@ -0,0 +1,84 @@
<?php
namespace Webkul\Product\Contracts\Criteria;
use Prettus\Repository\Contracts\CriteriaInterface;
use Prettus\Repository\Contracts\RepositoryInterface;
use Webkul\Product\Models\ProductAttributeValue;
use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\Product\Product\AbstractProduct;
/**
* Class MyCriteria.
*
* @package namespace App\Criteria;
*/
class AttributeToSelectCriteria extends AbstractProduct implements CriteriaInterface
{
/**
* @var AttributeRepository
*/
protected $attribute;
/**
* @var array|string
*/
protected $attributeToSelect;
/**
* @param Webkul\Attribute\Repositories\AttributeRepository $attribute
* @return void
*/
public function __construct(AttributeRepository $attribute)
{
$this->attribute = $attribute;
}
/**
* Set attributes in attributeToSelect variable
*
* @param array|string $attributes
*
* @return mixed
*/
public function addAttribueToSelect($attributes)
{
$this->attributeToSelect = $attributes;
return $this;
}
/**
* Apply criteria in query repository
*
* @param string $model
* @param RepositoryInterface $repository
*
* @return mixed
*/
public function apply($model, RepositoryInterface $repository)
{
$model = $model->select('products.*');
foreach ($this->attributeToSelect as $code) {
$attribute = $this->attribute->findOneByField('code', $code);
if(!$attribute)
continue;
$productValueAlias = 'pav_' . $attribute->code;
$model = $model->leftJoin('product_attribute_values as ' . $productValueAlias, function($qb) use($attribute, $productValueAlias) {
$qb = $this->applyChannelLocaleFilter($attribute, $qb, $productValueAlias);
$qb->on('products.id', $productValueAlias . '.product_id')
->where($productValueAlias . '.attribute_id', $attribute->id);
});
$model = $model->addSelect($productValueAlias . '.' . ProductAttributeValue::$attributeTypeFields[$attribute->type] . ' as ' . $code);
}
return $model;
}
}

View File

@ -0,0 +1,88 @@
<?php
namespace Webkul\Product\Contracts\Criteria;
use Prettus\Repository\Contracts\CriteriaInterface;
use Prettus\Repository\Contracts\RepositoryInterface;
use Webkul\Product\Models\ProductAttributeValue;
use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\Product\Product\AbstractProduct;
/**
* Class MyCriteria.
*
* @package namespace App\Criteria;
*/
class FilterByAttributesCriteria extends AbstractProduct implements CriteriaInterface
{
/**
* @var AttributeRepository
*/
protected $attribute;
/**
* @param Webkul\Attribute\Repositories\AttributeRepository $attribute
* @return void
*/
public function __construct(AttributeRepository $attribute)
{
$this->attribute = $attribute;
}
/**
* Apply criteria in query repository
*
* @param string $model
* @param RepositoryInterface $repository
*
* @return mixed
*/
public function apply($model, RepositoryInterface $repository)
{
$model = $model->leftJoin('products as variants', 'products.id', '=', 'variants.parent_id');
$model = $model->where(function($query1) use($model) {
$aliases = [
'products' => 'filter_',
'variants' => 'variant_filter_'
];
foreach($aliases as $table => $alias) {
$query1 = $query1->orWhere(function($query2) use($model, $table, $alias) {
foreach (request()->input() as $code => $value) {
$aliasTemp = $alias . $code;
$attribute = $this->attribute->findOneByField('code', $code);
if(!$attribute)
continue;
$model = $model->leftJoin('product_attribute_values as ' . $aliasTemp, $table . '.id', '=', $aliasTemp . '.product_id');
$query2 = $this->applyChannelLocaleFilter($attribute, $query2, $aliasTemp);
$column = ProductAttributeValue::$attributeTypeFields[$attribute->type];
$temp = explode(',', $value);
if($attribute->type != 'price') {
$query2 = $query2->where($aliasTemp . '.attribute_id', $attribute->id);
$query2 = $query2->where(function($query3) use($aliasTemp, $column, $temp) {
foreach($temp as $code => $filterValue) {
$query3 = $query3->orWhere($aliasTemp . '.' . $column, $filterValue);
}
});
} else {
$query2 = $query2->where($aliasTemp . '.' . $column, '>=', current($temp))
->where($aliasTemp . '.' . $column, '<=', end($temp))
->where($aliasTemp . '.attribute_id', $attribute->id);
}
}
});
}
});
return $model;
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace Webkul\Product\Contracts\Criteria;
use Prettus\Repository\Contracts\CriteriaInterface;
use Prettus\Repository\Contracts\RepositoryInterface;
/**
* Class MyCriteria.
*
* @package namespace App\Criteria;
*/
class FilterByCategoryCriteria implements CriteriaInterface
{
/**
* @var integer
*/
protected $categoryId;
/**
* @param integer $categoryId
* @return void
*/
public function __construct($categoryId)
{
$this->categoryId = $categoryId;
}
/**
* Apply criteria in query repository
*
* @param string $model
* @param RepositoryInterface $repository
*
* @return mixed
*/
public function apply($model, RepositoryInterface $repository)
{
$model = $model->leftJoin('product_categories', 'products.id', '=', 'product_categories.product_id')
->where('product_categories.category_id', $this->categoryId);
return $model;
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace Webkul\Product\Contracts\Criteria;
use Prettus\Repository\Contracts\CriteriaInterface;
use Prettus\Repository\Contracts\RepositoryInterface;
use Webkul\Product\Models\ProductAttributeValue;
use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\Product\Product\AbstractProduct;
/**
* Class MyCriteria.
*
* @package namespace App\Criteria;
*/
class SortCriteria extends AbstractProduct implements CriteriaInterface
{
/**
* @var AttributeRepository
*/
protected $attribute;
/**
* @param Webkul\Attribute\Repositories\AttributeRepository $attribute
* @return void
*/
public function __construct(AttributeRepository $attribute)
{
$this->attribute = $attribute;
}
/**
* Apply criteria in query repository
*
* @param string $model
* @param RepositoryInterface $repository
*
* @return mixed
*/
public function apply($model, RepositoryInterface $repository)
{
$params = request()->input();
if(isset($params['sort'])) {
if($params['sort'] == 'name' || $params['sort'] == 'price') {
$attribute = $this->attribute->findOneByField('code', $params['sort']);
$alias = 'sort_' . $params['sort'];
$model = $model->leftJoin('product_attribute_values as ' . $alias, function($qb) use($attribute, $alias) {
$qb = $this->applyChannelLocaleFilter($attribute, $qb, $alias);
$qb->on('products.id', $alias . '.product_id')
->where($alias . '.attribute_id', $attribute->id);
});
$model = $model->addSelect($alias . '.' . ProductAttributeValue::$attributeTypeFields[$attribute->type] . ' as ' . $attribute->code);
$model = $model->orderBy($attribute->code, $params['order']);
} else {
$model = $model->orderBy($params['sort'], $params['order']);
}
} else {
$model = $model->orderBy('created_at', 'desc');
}
return $model;
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace Webkul\Product\Database\Eloquent;
use Illuminate\Database\Eloquent\Builder as BaseBuilder;
use Illuminate\Pagination\Paginator;
/**
* @mixin \Illuminate\Database\Query\Builder
*/
class Builder extends BaseBuilder
{
/**
* Paginate the given query.
*
* @param int $perPage
* @param array $columns
* @param string $pageName
* @param int|null $page
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*
* @throws \InvalidArgumentException
*/
public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
{
$page = $page ?: Paginator::resolveCurrentPage($pageName);
$perPage = $perPage ?: $this->model->getPerPage();
$results = ($total = $this->toBase()->getCountForPagination($columns))
? $this->forPage($page, $perPage)->get($columns)
: $this->model->newCollection();
return $this->paginator($results, $total, $perPage, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]);
}
}

View File

@ -111,7 +111,7 @@ class Product extends Model
*/
public function up_sells()
{
return $this->belongsToMany(self::class, 'product_up_sells');
return $this->belongsToMany(self::class, 'product_up_sells', 'parent_id', 'child_id');
}
/**
@ -139,9 +139,9 @@ class Product extends Model
* @return mixed
*/
public function getAttribute($key)
{
{
if (!method_exists(self::class, $key) && !in_array($key, ['parent_id', 'attribute_family_id']) && !isset($this->attributes[$key])) {
if ($this->isCustomAttribute($key)) {
if (isset($this->id) && $this->isCustomAttribute($key)) {
$this->attributes[$key] = '';
$attributeModel = $this->attribute_family->custom_attributes()->where('attributes.code', $key)->first();
@ -185,32 +185,46 @@ class Product extends Model
$hiddenAttributes = $this->getHidden();
$channel = request()->get('channel') ?: core()->getCurrentChannelCode();
if(isset($this->id)) {
$channel = request()->get('channel') ?: core()->getCurrentChannelCode();
$locale = request()->get('locale') ?: app()->getLocale();
$locale = request()->get('locale') ?: app()->getLocale();
foreach ($this->attribute_family->custom_attributes as $attribute) {
if (in_array($attribute->code, $hiddenAttributes)) {
continue;
}
if($attribute->value_per_channel) {
if($attribute->value_per_locale) {
$attributeValue = $this->attribute_values()->where('channel', $channel)->where('locale', $locale)->where('attribute_id', $attribute->id)->first();
} else {
$attributeValue = $this->attribute_values()->where('channel', $channel)->where('attribute_id', $attribute->id)->first();
foreach ($this->attribute_family->custom_attributes as $attribute) {
if (in_array($attribute->code, $hiddenAttributes)) {
continue;
}
} else {
if($attribute->value_per_locale) {
$attributeValue = $this->attribute_values()->where('locale', $locale)->where('attribute_id', $attribute->id)->first();
} else {
$attributeValue = $this->attribute_values()->where('attribute_id', $attribute->id)->first();
}
}
$attributes[$attribute->code] = $attributeValue[ProductAttributeValue::$attributeTypeFields[$attribute->type]];
if($attribute->value_per_channel) {
if($attribute->value_per_locale) {
$attributeValue = $this->attribute_values()->where('channel', $channel)->where('locale', $locale)->where('attribute_id', $attribute->id)->first();
} else {
$attributeValue = $this->attribute_values()->where('channel', $channel)->where('attribute_id', $attribute->id)->first();
}
} else {
if($attribute->value_per_locale) {
$attributeValue = $this->attribute_values()->where('locale', $locale)->where('attribute_id', $attribute->id)->first();
} else {
$attributeValue = $this->attribute_values()->where('attribute_id', $attribute->id)->first();
}
}
$attributes[$attribute->code] = $attributeValue[ProductAttributeValue::$attributeTypeFields[$attribute->type]];
}
}
return $attributes;
}
/**
* Overrides the default Eloquent query builder
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function newEloquentBuilder($query)
{
return new \Webkul\Product\Database\Eloquent\Builder($query);
}
}

View File

@ -3,8 +3,17 @@
namespace Webkul\Product\Models;
use Illuminate\Database\Eloquent\Model;
use Webkul\Customer\Models\Customer;
class ProductReview extends Model
{
protected $fillable = [];
protected $fillable = ['comment','title','rating','status','product_id','customer_id'];
/**
* Get the product attribute family that owns the product.
*/
public function customer()
{
return $this->belongsTo(Customer::class);
}
}

View File

@ -35,30 +35,4 @@ abstract class AbstractProduct
return $qb;
}
/**
* Adds attributes to select
*
* @param QB $qb
* @return QB
*/
public function addSelectAttributes($qb)
{
foreach ($this->attributeToSelect as $code) {
$attribute = $this->attribute->findOneByField('code', $code);
$productValueAlias = 'pav_' . $attribute->code;
$qb->leftJoin('product_attribute_values as ' . $productValueAlias, function($leftJoin) use($attribute, $productValueAlias) {
$leftJoin->on('products.id', $productValueAlias . '.product_id');
$leftJoin = $this->applyChannelLocaleFilter($attribute, $leftJoin, $productValueAlias)->where($productValueAlias . '.attribute_id', $attribute->id);
});
$qb->addSelect($productValueAlias . '.' . ProductAttributeValue::$attributeTypeFields[$attribute->type] . ' as ' . $code);
}
return $qb;
}
}

View File

@ -1,94 +0,0 @@
<?php
namespace Webkul\Product\Product;
use Illuminate\Support\Facades\DB;
use Webkul\Product\Repositories\ProductRepository as Product;
use Webkul\Attribute\Repositories\AttributeRepository as Attribute;
class Collection extends AbstractProduct
{
/**
* ProductRepository object
*
* @var array
*/
protected $product;
/**
* AttributeRepository object
*
* @var array
*/
protected $attribute;
/**
* array object
*
* @var array
*/
protected $attributeToSelect = [
'name',
'description',
'short_description',
'price',
'special_price',
'special_price_from',
'special_price_to'
];
/**
* Create a new controller instance.
*
* @param Webkul\Product\Repositories\ProductRepository $product
* @param Webkul\Attribute\Repositories\AttributeRepository $attribute
* @return void
*/
public function __construct(Product $product, Attribute $attribute)
{
$this->product = $product;
$this->attribute = $attribute;
}
/**
* @param array $attributes
* @return Void
*/
public function addAttributesToSelect($attributes)
{
$this->attributeToSelect = array_unique(
array_merge($this->attributeToSelect, $attributes)
);
return $this;
}
/**
* @param integer $categoryId
* @return Collection
*/
public function getCollection($categoryId = null)
{
$qb = $this->product->getModel()
->select('products.*')
->join('product_categories', 'products.id', '=', 'product_categories.product_id')
->where('product_categories.category_id', $categoryId);
$this->addSelectAttributes($qb);
// foreach (request()->input() as $code => $value) {
// $filterAlias = 'filter_' . $code;
// $qb->leftJoin('product_attribute_values as ' . $filterAlias, 'products.id', '=', $filterAlias . '.product_id');
// $qb->where($filterAlias . '.' . ProductAttributeValue::$attributeTypeFields[$attribute->type], $value);
// }
// if(0) {
// $qb->orderBy('id', 'desc');
// }
return $qb->paginate(9);
}
}

View File

@ -1,16 +1,96 @@
<?php
namespace Webkul\Shop\Product;
namespace Webkul\Product\Product;
class Review extends AbstractProduct
{
/**
* Returns the product's avg rating
*
* @param Product $product
* @return float
*/
public function getAverageRating($product)
{
return round($product->reviews->average('rating'));
return round($product->reviews->where('status',1)->average('rating'));
}
/**
* Returns the total review of the product
*
* @param Product $product
* @return integer
*/
public function getTotalReviews($product)
{
return $product->reviews()->where('status',1)->count();
}
/**
* Returns the formated created at date
*
* @param ProductReview $review
* @return integer
*/
public function formatDate($reviewCreatedAt)
{
return core()->formatDate($reviewCreatedAt, 'd, M Y');
}
/**
* Returns the total rating of the product
*
* @param Product $product
* @return integer
*/
public function getTotalRating($product)
{
return $product->reviews()->where('status',1)->sum('rating');
}
/**
* Returns the Percentage rating of the product
*
* @param Product $product
* @return integer
*/
public function getPercentageRating($product)
{
$reviews['five'] = $product->reviews()->where('rating', 5)->where('status',1)->count();
$reviews['four'] = $product->reviews()->where('rating', 4)->where('status',1)->count();
$reviews['three'] = $product->reviews()->where('rating', 3)->where('status',1)->count();
$reviews['two'] = $product->reviews()->where('rating', 2)->where('status',1)->count();
$reviews['one'] = $product->reviews()->where('rating', 1)->where('status',1)->count();
foreach($reviews as $key=>$review){
if($this->getTotalReviews($product) == 0){
$percentage[$key]=0;
}else{
$percentage[$key] = round(($review/$this->getTotalReviews($product))*100);
}
}
return $percentage;
}
/**
* Returns the of the product
*
* @param Product $product
* @return integer
*/
public function loadMore($product)
{
$link = $_SERVER['PHP_SELF'];
$link_array = explode('/',$link);
$last=end($link_array);
$itemPerPage = $last*5;
return $product->reviews()->where('status',1)->paginate($itemPerPage);
}
}

View File

@ -0,0 +1,142 @@
<?php
namespace Webkul\Product\Product;
class Toolbar extends AbstractProduct
{
/**
* Returns available sort orders
*
* @param string $key
* @return string
*/
public function getAvailableOrders()
{
return [
'name-asc' => 'from-a-z',
'name-desc' => 'from-z-a',
'created_at-desc' => 'newest-first',
'created_at-asc' => 'oldest-first',
'price-asc' => 'cheapest-first',
'price-desc' => 'expansive-first'
];
}
/**
* Returns available limits
*
* @param string $key
* @return string
*/
public function getAvailableLimits()
{
return [9, 15, 21, 28];
}
/**
* Returns the sort order url
*
* @param string $key
* @return string
*/
public function getOrderUrl($key)
{
$keys = explode('-', $key);
return request()->fullUrlWithQuery([
'sort' => current($keys),
'order' => end($keys)
]);
}
/**
* Returns the limit url
*
* @param integer $limit
* @return string
*/
public function getLimitUrl($limit)
{
return request()->fullUrlWithQuery([
'limit' => $limit
]);
}
/**
* Returns the mode url
*
* @param string $mode
* @return string
*/
public function getModeUrl($mode)
{
return request()->fullUrlWithQuery([
'mode' => $mode
]);
}
/**
* Checks if sort order is active
*
* @param string $key
* @return boolean
*/
public function isOrderCurrent($key)
{
$params = request()->input();
if(isset($params['sort']) && $key == $params['sort'] . '-' . $params['order'])
return true;
elseif(!isset($params['sort']) && $key == 'created_at-desc')
return true;
return false;
}
/**
* Checks if limit is active
*
* @param integer $limit
* @return boolean
*/
public function isLimitCurrent($limit)
{
$params = request()->input();
if(isset($params['limit']) && $limit == $params['limit'])
return true;
return false;
}
/**
* Checks if mode is active
*
* @param string $key
* @return boolean
*/
public function isModeActive($key)
{
$params = request()->input();
if(isset($params['mode']) && $key == $params['mode'])
return true;
return false;
}
/**
* Returns the current mode
*
* @param string $mode
* @return string
*/
public function getCurrentMode()
{
$params = request()->input();
if(isset($params['mode']))
return $params['mode'];
return 'grid';
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace Webkul\Product\Product;
class View extends AbstractProduct
{
/**
* Returns the visible custom attributes
*
* @param Product $product
* @return integer
*/
public function getAdditionalData($product)
{
$data = [];
$attributes = $product->attribute_family->custom_attributes;
foreach($attributes as $attribute) {
if($attribute->is_visible_on_front) {
$data[] = [
'code' => $attribute->code,
'label' => $attribute->name,
'value' => $product->{$attribute->code},
];
}
}
return $data;
}
}

View File

@ -74,7 +74,7 @@ class ProductAttributeValueRepository extends Repository
*/
public function isValueUnique($productId, $attributeId, $column, $value)
{
$result = $this->resetScope()->model->where($column, $value)->where('attribute_id', '!=', $attributeId)->where('product_id', '!=', $productId)->get();
$result = $this->resetScope()->model->where($column, $value)->where('attribute_id', '=', $attributeId)->where('product_id', '!=', $productId)->get();
return $result->count() ? false : true;
}

View File

@ -10,6 +10,11 @@ use Webkul\Product\Repositories\ProductAttributeValueRepository;
use Webkul\Product\Repositories\ProductInventoryRepository;
use Webkul\Product\Repositories\ProductImageRepository;
use Webkul\Product\Models\ProductAttributeValue;
use Webkul\Product\Contracts\Criteria\SortCriteria;
use Webkul\Product\Contracts\Criteria\AttributeToSelectCriteria;
use Webkul\Product\Contracts\Criteria\FilterByAttributesCriteria;
use Webkul\Product\Contracts\Criteria\FilterByCategoryCriteria;
use Illuminate\Database\Eloquent\ModelNotFoundException;
/**
* Product Repository
@ -177,6 +182,8 @@ class ProductRepository extends Repository
}
}
$previousVariantIds = $product->variants->pluck('id');
if(isset($data['variants'])) {
foreach ($data['variants'] as $variantId => $variantData) {
if (str_contains($variantId, 'variant_')) {
@ -187,13 +194,22 @@ class ProductRepository extends Repository
$this->createVariant($product, $permutation, $variantData);
} else {
if(is_numeric($index = $previousVariantIds->search($variantId))) {
$previousVariantIds->forget($index);
}
$variantData['channel'] = $data['channel'];
$variantData['locale'] = $data['locale'];
$this->updateVariant($variantData, $variantId);
}
}
}
foreach ($previousVariantIds as $variantId) {
$this->delete($variantId);
}
$this->productInventory->saveInventories($data, $product);
$this->productImage->uploadImages($data, $product);
@ -358,4 +374,53 @@ class ProductRepository extends Repository
return false;
}
/**
* @param integer $categoryId
* @return Collection
*/
public function findAllByCategory($categoryId = null)
{
$this->pushCriteria(app(SortCriteria::class));
$this->pushCriteria(app(FilterByAttributesCriteria::class));
$this->pushCriteria(new FilterByCategoryCriteria($categoryId));
$this->pushCriteria(app(AttributeToSelectCriteria::class)->addAttribueToSelect([
'name',
'description',
'short_description',
'price',
'special_price',
'special_price_from',
'special_price_to'
]));
$params = request()->input();
return $this->scopeQuery(function($query){
return $query->distinct()->addSelect('products.*');
})->paginate(isset($params['limit']) ? $params['limit'] : 9, ['products.id']);
}
/**
* Retrive product from slug
*
* @param string $slug
* @return mixed
*/
public function findBySlugOrFail($slug)
{
$attribute = $this->attribute->findOneByField('code', 'url_key');
$attributeValue = $this->attributeValue->findOneWhere([
'attribute_id' => $attribute->id,
ProductAttributeValue::$attributeTypeFields[$attribute->type] => $slug
]);
if($attributeValue && $attributeValue->product)
return $attributeValue->product;
throw (new ModelNotFoundException)->setModel(
get_class($this->model), $slug
);
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace Webkul\Product\Repositories;
use Webkul\Core\Eloquent\Repository;
/**
* Product Review Reposotory
*
* @author Jitendra Singh <jitendra@webkul.com>
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class ProductReviewRepository extends Repository
{
/**
* Specify Model class name
*
* @return mixed
*/
function model()
{
return 'Webkul\Product\Models\ProductReview';
}
}

View File

@ -0,0 +1,57 @@
<?php
namespace Webkul\Shop\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Webkul\Product\Repositories\ProductRepository as Product;
/**
* Product controller
*
* @author Jitendra Singh <jitendra@webkul.com>
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class ProductController extends Controller
{
/**
* Contains route related configuration
*
* @var array
*/
protected $_config;
/**
* ProductRepository object
*
* @var array
*/
protected $product;
/**
* Create a new controller instance.
*
* @param Webkul\Product\Repositories\ProductRepository $product
* @return void
*/
public function __construct( Product $product)
{
$this->product = $product;
$this->_config = request('_config');
}
/**
* Display a listing of the resource.
*
* @param string $slug
* @return \Illuminate\Http\Response
*/
public function index($slug)
{
$product = $this->product->findBySlugOrFail($slug);
return view($this->_config['view'], compact('product'));
}
}

View File

@ -0,0 +1,150 @@
<?php
namespace Webkul\Shop\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Webkul\Product\Repositories\ProductRepository as Product;
use Webkul\Product\Repositories\ProductReviewRepository as ProductReview;
/**
* Review controller
*
* @author Jitendra Singh <jitendra@webkul.com>
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class ReviewController extends Controller
{
/**
* Contains route related configuration
*
* @var array
*/
protected $_config;
/**
* ProductRepository object
*
* @var array
*/
protected $product;
/**
* ProductReviewRepository object
*
* @var array
*/
protected $productReview;
/**
* Create a new controller instance.
*
* @param Webkul\Product\Repositories\ProductRepository $product
* @param Webkul\Product\Repositories\ProductReviewRepository $productReview
* @return void
*/
public function __construct(Product $product, ProductReview $productReview)
{
$this->product = $product;
$this->productReview = $productReview;
$this->_config = request('_config');
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
return view($this->_config['view']);
}
/**
* Show the form for creating a new resource.
*
* @param string $slug
* @return \Illuminate\Http\Response
*/
public function create($slug)
{
$product = $this->product->findBySlugOrFail($slug);
return view($this->_config['view'], compact('product'));
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request , $id)
{
$this->validate(request(), [
'comment' => 'required',
'rating' => 'required',
'title' => 'required',
]);
$data=$request->all();
$customer_id = auth()->guard('customer')->user()->id;
$data['status']=0;
$data['product_id']=$id;
$data['customer_id']=$customer_id;
$this->productReview->create($data);
session()->flash('success', 'Review submitted successfully.');
return redirect()->route($this->_config['redirect']);
}
/**
* Display reviews accroding to product.
*
* @param string $slug
* @return \Illuminate\Http\Response
*/
public function show($slug)
{
$product = $this->product->findBySlugOrFail($slug);
return view($this->_config['view'],compact('product'));
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
$review = $this->productReview->find($id);
return view($this->_config['view'],compact('review'));
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
$this->productReview->update(request()->all(), $id);
session()->flash('success', 'Review updated successfully.');
return redirect()->route($this->_config['redirect']);
}
}

View File

@ -9,7 +9,7 @@ Route::group(['middleware' => ['web']], function () {
Route::get('/categories/{slug}', 'Webkul\Shop\Http\Controllers\CategoryController@index')->defaults('_config', [
'view' => 'shop::products.index'
]);
/* dummy routes */
Route::view('/customer/order','shop::customers.account.orders.index');
@ -24,9 +24,33 @@ Route::group(['middleware' => ['web']], function () {
Route::view('/customer/payment_complete','shop::customers.checkout.complete');
/* dummy routes ends here */
Route::get('/products/{slug}', 'Webkul\Shop\Http\Controllers\ProductController@index')->defaults('_config', [
'view' => 'shop::products.view'
])->name('shop.products.index');
// Product Review routes
Route::get('/reviews/{slug}/{id}', 'Webkul\Shop\Http\Controllers\ReviewController@show')->defaults('_config', [
'view' => 'shop::products.reviews.index'
])->name('shop.reviews.index');
Route::get('/product/{slug}/review', 'Webkul\Shop\Http\Controllers\ReviewController@create')->defaults('_config', [
'view' => 'shop::products.reviews.create'
])->name('shop.reviews.create');
Route::post('/product/{slug}/review', 'Webkul\Shop\Http\Controllers\ReviewController@store')->defaults('_config', [
'redirect' => 'shop.reviews.index'
])->name('shop.reviews.store');
// Route::post('/reviews/create/{slug}', 'Webkul\Core\Http\Controllers\ReviewController@store')->defaults('_config', [
// 'redirect' => 'admin.reviews.index'
// ])->name('admin.reviews.store');
Route::view('/cart', 'shop::store.product.view.cart.index');
Route::view('/products/{slug}', 'shop::store.product.details.index');
// Route::view('/products/{slug}', 'shop::products.view');
//customer routes starts here
Route::prefix('customer')->group(function () {

View File

@ -1,4 +1,6 @@
//shop variables
$font-color: #242424;
$font-size-base: 16px;
$font-name: "Montserrat", sans-serif;
$background-color: #f2f2f2;
$footer-back: #f2f2f2;
@ -23,6 +25,7 @@ $horizontal-rule-color: #E8E8E8;
//product
$real-price:#A5A5A5;
$product-font-color: #242424;
$product-special-price-color: #FF6472;
$product-price-color: #FF6472;
$dark-blue-shade: #0031F0;
$bar-color: #D8D8D8;

View File

@ -8,7 +8,8 @@ body {
margin: 0;
padding: 0;
font-weight: 500;
font-size: 14px;
color: $font-color;
font-size: $font-size-base;
}
* {
@ -200,7 +201,7 @@ body {
.nav a {
display:block;
color: #242424;
color: $font-color;
text-decoration: none;
padding: 0.8em 0.3em 0.8em 0.5em;
text-transform: uppercase;
@ -674,13 +675,13 @@ section.slider-block {
.layered-filter-wrapper {
width: 25%;
float: left;
margin-right: 20px;
padding-right: 20px;
min-height: 1px;
.filter-title {
border-bottom: 1px solid #E8E8E8;
font-size: 16px;
color: #242424;
color: $font-color;
padding: 10px 0;
}
@ -760,6 +761,7 @@ section.slider-block {
}
}
.main-container-wrapper {
margin-left: 10%;
margin-right: 10%;
@ -769,6 +771,11 @@ section.slider-block {
width: 100%;
}
.main {
display: inline-block;
width: 75%
}
.product-grid {
display: grid;
grid-gap: 30px;
@ -789,58 +796,129 @@ section.slider-block {
display: flex;
flex-flow: column;
justify-content: center;
}
}
.product-image img {
align-self: center;
width: 100%;
margin-bottom: 14px;
.product-card {
.product-image img {
align-self: center;
width: 100%;
margin-bottom: 14px;
}
.product-name {
font-size: 16px;
margin-bottom: 14px;
width: 100%;
color: $font-color;
a {
color: $font-color;
}
}
.product-description {
font-size: 16px;
margin-bottom: 14px;
display: none;
}
.product-ratings {
width: 100%;
margin-bottom: 14px;
}
.cart-fav-seg {
display: inline-flex;
width: 100%;
align-items: center;
.addtocart {
border-radius: 0px;
margin-right: 10px;
text-transform: uppercase;
}
}
}
.product-list {
.product-card {
width: 100%;
display: inline-block;
margin-bottom: 20px;
.product-image {
float: left;
width: 30%;
height: 350px;
img {
height: 100%;
}
}
.product-name {
.product-information {
float: right;
width: 70%;
padding-left: 30px;
}
&:last-child {
margin-bottom: 0;
}
}
}
.top-toolbar {
width: 100%;
display: inline-block;
margin-bottom: 25px;
.page-info {
float: left;
color: $font-color;
line-height: 45px;
}
.pager {
float: right;
label {
font-size: 16px;
margin-bottom: 14px;
width: 100%;
margin-right: 5px;
}
.product-price {
select {
background: #FFFFFF;
border: 1px solid #C7C7C7;
border-radius: 3px;
font-size: 16px;
margin-bottom: 14px;
width: 100%;
font-weight: 600;
color: $font-color;
padding: 10px;
}
.price-label {
font-size: 14px;
font-weight: 400;
}
.view-mode {
display: inline-block;
margin-right: 20px;
.regular-price {
font-size: 16px;
color: #A5A5A5;
text-decoration: line-through;
margin-right: 10px;
}
a, span {
display: inline-block;
vertical-align: middle;
.special-price {
font-size: 16px;
color: #FF6472;
&.grid-view {
margin-right: 10px;
}
}
}
.product-ratings {
width: 100%;
margin-bottom: 14px;
.sorter {
display: inline-block;
margin-right: 10px;
}
.cart-fav-seg {
display: inline-flex;
width: 100%;
align-items: center;
.addtocart {
border-radius: 0px;
margin-right: 10px;
text-transform: uppercase;
}
.limiter {
display: inline-block;
}
}
}
@ -920,6 +998,30 @@ section.slider-block {
}
}
.product-price {
font-size: 16px;
margin-bottom: 14px;
width: 100%;
font-weight: 600;
.price-label {
font-size: 14px;
font-weight: 400;
}
.regular-price {
font-size: 16px;
color: #A5A5A5;
text-decoration: line-through;
margin-right: 10px;
}
.special-price {
font-size: 16px;
color: #FF6472;
}
}
.footer {
background-color: $footer-back;
padding-left: 10%;
@ -1123,7 +1225,7 @@ section.slider-block {
.section-head {
.profile-heading {
font-size: 28px;
color: #242424;
color: $font-color;
text-transform: capitalize;
text-align: left;
}
@ -1230,24 +1332,16 @@ section.product-detail, section.product-review {
margin-bottom: 20px;
}
.price {
.product-price {
margin-bottom: 14px;
.main-price {
font-size: 24px;
color: $product-price-color;
}
.real-price {
color: $real-price;
text-decoration-line: line-through;
}
}
}
}
.rating-reviews {
margin-top: 30px;
margin-top: 0px;
width: 50%;
margin-left: 20px;
.title-inline {
display: inline-flex;
@ -1298,14 +1392,11 @@ section.product-detail, section.product-review {
background: $bar-color;
.line-value {
height: 4px;
width: 100px;
background-color: $dark-blue-shade;
}
}
}
}
}
.reviews {
@ -1377,12 +1468,12 @@ section.product-detail, section.product-review {
margin-bottom: 14px;
}
.price {
.product-price {
margin-bottom: 14px;
font-size: 24px;
.main-price {
.special-price {
font-size: 24px;
color: $product-price-color;
}
}
@ -1394,9 +1485,21 @@ section.product-detail, section.product-review {
margin-bottom: 14px;
}
hr{
border-top: 1px solid $horizontal-rule-color;
margin-bottom: 17px;
.full-specifications {
td {
padding: 10px 0;
color: #5E5E5E;
&:first-child {
padding-right: 40px;
}
}
}
.accordian .accordian-header {
font-size: 16px;
padding-left: 0;
font-weight: 600;
}
.attributes {
@ -1478,21 +1581,21 @@ section.product-detail, section.product-review {
font-size: 16px;
}
.full-specification{
}
.rating-reviews {
margin-top: 30px;
.title{
.title {
margin-bottom: 15px;
font-weight: 600;
}
.overall {
margin-bottom: 5px;
.number{
font-size: 34px;
.review-info {
.number {
font-size: 34px;
}
}
button {
@ -1500,7 +1603,6 @@ section.product-detail, section.product-review {
border-radius: 0px !important;
}
margin-bottom: 5px;
}
.reviews {
@ -1512,11 +1614,23 @@ section.product-detail, section.product-review {
.stars {
margin-bottom: 15px;
display: inline-block;
.icon {
width: 18px;
height: 18px;
}
}
.message {
margin-bottom: 10px;
}
.reviewer-details {
color: #5E5E5E;
}
}
.view-all {
margin-top:15px;
color: $logo-color;
@ -1525,33 +1639,7 @@ section.product-detail, section.product-review {
}
}
}
}
// .related-products-wrapper {
// margin-bottom: 80px;
// .title{
// margin-bottom: 22px;
// text-align: center;
// }
// .horizontal-rule {
// height: 1px;
// background: $horizontal-rule-color;
// width: 148px;
// margin-bottom: 24px;
// margin-left:auto;
// margin-right:auto;
// }
// .related-products {
// display: grid;
// grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
// grid-gap: 10px;
// }
// }
}
/* cart pages and elements css begins here */
@ -1780,14 +1868,25 @@ section.cart {
}
.related-products-wrapper {
.attached-products-wrapper {
margin-bottom: 80px;
.title{
margin-bottom: 22px;
.title {
margin-bottom: 40px;
font-size: 18px;
color: $product-font-color;
text-align: center;
position: relative;
.border-bottom {
border-bottom: 1px solid rgba(162, 162, 162, 0.2);
display: inline-block;
width: 100px;
position: absolute;
top: 40px;
left: 50%;
margin-left: -50px;
}
}
.horizontal-rule {
@ -1798,13 +1897,6 @@ section.cart {
margin-left:auto;
margin-right:auto;
}
.related-products {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
grid-gap: 10px;
}
}
// order page css start here
@ -3648,4 +3740,184 @@ section.cart {
// complete page end here
// review page start here
section.review {
font-size: 16px;
color: $product-font-color;
.category-breadcrumbs {
display: inline;
}
.review-layouter {
display: flex;
flex-flow: row;
margin-top: 20px;
.product-info {
.image {
border:1px solid red;
img {
height: 280px;
width: 280px;
}
}
.heading {
margin-top: 20px;
span {
font-size: 24px;
color: #242424;
letter-spacing: -0.58px;
}
}
.price {
margin-top: 10px;
.pro-price {
font-size: 24px;
color: #FF6472;
letter-spacing: -0.58px;
}
.pro-price-not {
margin-left: 10px;
font-size: 16px;
color: #A5A5A5;
letter-spacing: -0.26px;
}
.offer {
margin-left: 10px;
font-size: 16px;
color: #242424;
letter-spacing: -0.26px;
}
}
}
.review-info {
margin-left: 20px;
width: 49%;
.heading {
margin-top: 10px;
span {
font-size: 16px;
color: #242424;
letter-spacing: -0.26px;
}
.btn.btn-primary.right {
float: right;
margin-top: -10px;
}
}
.rating {
margin-top : 25px;
font-size: 16px;
color: #5E5E5E;
letter-spacing: -0.12px;
span {
display: inline;
}
}
.stars {
width: 270px;
display: inline-block;
label.star {
font-size: 36px;
color: #d4d4d4;
transition: all .2s;
}
label.star:before {
content: '\2605';
}
}
.write-review {
margin-top: 25px;
.control-group {
margin-bottom: 0px;
textarea {
margin-top: 5px;
border: 2px solid #C7C7C7;
border-radius: 3px;
width: 600px;
height: 120px;
}
}
}
.submit-button {
margin-top: 10px;
button {
background: #0031F0;
font-size: 14px;
color: #FFFFFF;
letter-spacing: -0.26px;
text-align: center;
width: 120px;
height: 38px;
border: none;
}
}
.review-detail{
height: 150px;
border: 1px solid firebrick;
margin-top: 30px;
display: flex;
flex-direction: row;
.rating-review {
margin-top: 40px;
margin-left: 20px;
width: 48%;
.avg-rating-count{
span {
font-size: 34px;
color: #242424;
letter-spacing: -0.82px;
text-align: center;
}
}
}
.rating-calculate {
.progress-only {
width:20px;
border: 1px solid blue;
}
}
}
}
}
}
// review page start here

View File

@ -2,10 +2,23 @@
display: inline-block;
background-size: cover;
}
.dropdown-right-icon{
background-image:URL('../images/icon-dropdown-left.svg');
width: 8px;
height: 8px;
margin-left:auto;
margin-bottom: 2px;
}
.grid-view-icon {
background-image:URL('../images/icon-grid-view.svg');
width: 24px;
height: 24px;
}
.list-view-icon {
background-image:URL('../images/icon-list-view.svg');
width: 24px;
height: 24px;
}

View File

@ -35,6 +35,20 @@ return [
'products' => [
'layered-nav-title' => 'Shop By',
'price-label' => 'As low as',
'remove-filter-link-title' => 'Clear All'
'remove-filter-link-title' => 'Clear All',
'sort-by' => 'Sort By',
'from-a-z' => 'From A-Z',
'from-z-a' => 'From Z-A',
'newest-first' => 'Newest First',
'oldest-first' => 'Oldest First',
'cheapest-first' => 'Cheapest First',
'expansive-first' => 'Expansive First',
'show' => 'Show',
'pager-info' => 'Showing :showing of :total Items',
'description' => 'Description',
'specification' => 'Specification',
'total-reviews' => ':total Reviews',
'by' => 'By :name',
'up-sell-title' => 'We found other products you might like!'
]
];

View File

@ -1 +1 @@
<button class="btn btn-md btn-primary addtocart">Add to Cart</button>
<button class="btn btn-lg btn-primary addtocart">Add to Cart</button>

View File

@ -1,20 +0,0 @@
<div class="product-card">
<div class="product-image">
<img src="{{ bagisto_asset('images/gogs.png') }}" />
</div>
<div class="product-name">
<span>{{ $product->name }}</span>
</div>
@include ('shop::products.price', ['product' => $product])
@if ($product->reviews->count())
@include ('shop::products.review', ['product' => $product])
@endif
@include ('shop::products.add-to', ['product' => $product])
</div>

View File

@ -2,24 +2,40 @@
@section('content-wrapper')
@include ('shop::products.layered-navigation')
@include ('shop::products.list.layered-navigation')
<div class="main" style="display: inline-block">
<div class="product-grid max-3-col">
@inject ('productRepository', 'Webkul\Product\Repositories\ProductRepository')
@inject ('productHelper', 'Webkul\Product\Product\Collection')
<?php $products = $productHelper->getCollection($category->id); ?>
@foreach ($products as $product)
<?php $products = $productRepository->findAllByCategory($category->id); ?>
@include ('shop::products.card', ['product' => $product])
@include ('shop::products.list.toolbar')
@endforeach
@inject ('toolbarHelper', 'Webkul\Product\Product\Toolbar')
</div>
@if ($toolbarHelper->getCurrentMode() == 'grid')
<div class="product-grid max-3-col">
@foreach ($products as $product)
@include ('shop::products.list.card', ['product' => $product])
@endforeach
</div>
@else
<div class="product-list">
@foreach ($products as $product)
@include ('shop::products.list.card', ['product' => $product])
@endforeach
</div>
@endif
<div class="bottom-toolbar">
{{ $products->appends(request()->input())->links() }}
@ -28,8 +44,4 @@
</div>
@stop
@push('scripts')
@endpush
@stop

View File

@ -0,0 +1,35 @@
<div class="product-card">
<div class="product-image">
<a href="{{ route('shop.products.index', $product->url_key) }}" title="{{ $product->name }}">
<img src="{{ bagisto_asset('images/gogs.png') }}" />
</a>
</div>
<div class="product-information">
<div class="product-name">
{{ $product->id }}
<a href="" title="{{ $product->name }}">
<span>{{ $product->name }}</span>
</a>
</div>
<div class="product-description">
{{ $product->short_description }}
</div>
@include ('shop::products.price', ['product' => $product])
@if ($product->reviews->count())
@include ('shop::products.review', ['product' => $product])
@endif
@include ('shop::products.add-to', ['product' => $product])
</div>
</div>

View File

@ -1,7 +1,9 @@
@inject ('attributeRepository', 'Webkul\Attribute\Repositories\AttributeRepository')
<div class="layered-filter-wrapper">
<layered-navigation></layered-navigation>
</div>
@push('scripts')
@ -129,8 +131,8 @@
sliderConfig: {
value: [
100,
250
0,
0
],
max: 500,
processStyle: {
@ -171,7 +173,7 @@
clearFilters () {
if(this.attribute.type == 'price') {
this.sliderConfig.value = [100, 250];
this.sliderConfig.value = [0, 0];
}
this.appliedFilters = [];

View File

@ -0,0 +1,67 @@
@inject ('toolbarHelper', 'Webkul\Product\Product\Toolbar')
<div class="top-toolbar">
<div class="page-info">
{{ __('shop::app.products.pager-info', ['showing' => $products->firstItem() . '-' . $products->lastItem(), 'total' => $products->total()]) }}
</div>
<div class="pager">
<div class="view-mode">
@if ($toolbarHelper->isModeActive('grid'))
<span class="grid-view">
<i class="icon grid-view-icon"></i>
</span>
@else
<a href="{{ $toolbarHelper->getModeUrl('grid') }}" class="grid-view">
<i class="icon grid-view-icon"></i>
</a>
@endif
@if ($toolbarHelper->isModeActive('list'))
<span class="list-view">
<i class="icon list-view-icon"></i>
</span>
@else
<a href="{{ $toolbarHelper->getModeUrl('list') }}" class="list-view">
<i class="icon list-view-icon"></i>
</a>
@endif
</div>
<div class="sorter">
<label>{{ __('shop::app.products.sort-by') }}</label>
<select onchange="window.location.href = this.value">
@foreach ($toolbarHelper->getAvailableOrders() as $key => $order)
<option value="{{ $toolbarHelper->getOrderUrl($key) }}" {{ $toolbarHelper->isOrderCurrent($key) ? 'selected' : '' }}>
{{ __('shop::app.products.' . $order) }}
</option>
@endforeach
</select>
</div>
<div class="limiter">
<label>{{ __('shop::app.products.show') }}</label>
<select onchange="window.location.href = this.value">
@foreach ($toolbarHelper->getAvailableLimits() as $limit)
<option value="{{ $toolbarHelper->getLimitUrl($limit) }}" {{ $toolbarHelper->isLimitCurrent($limit) ? 'selected' : '' }}>
{{ $limit }}
</option>
@endforeach
</select>
</div>
</div>
</div>

View File

@ -0,0 +1,115 @@
@extends('shop::layouts.master')
@section('content-wrapper')
<section class="review">
<div class="category-breadcrumbs">
<span class="breadcrumb">Home</span> > <span class="breadcrumb">Men</span> > <span class="breadcrumb">Slit Open Jeans</span>
</div>
<div class="review-layouter">
<div class="product-info">
<div class="image">
<img src="{{ bagisto_asset('images/jeans_big.jpg') }}" />
</div>
<div class="heading">
<span>{{ $product->name }}</span>
</div>
<div class="price">
@inject ('priceHelper', 'Webkul\Product\Product\Price')
@if ($product->type == 'configurable')
<span class="pro-price">{{ core()->currency($priceHelper->getMinimalPrice($product)) }}</span>
@else
@if ($priceHelper->haveSpecialPrice($product))
<span class="pro-price">{{ core()->currency($priceHelper->getSpecialPrice($product)) }}</span>
@else
<span class="pro-price">{{ core()->currency($product->price) }}</span>
@endif
@endif
<span class="pro-price-not">
<strike> $45.00 </strike>
</span>
<span class="offer"> 10% Off </span>
</div>
</div>
<div class="review-info">
<form method="POST" action="{{ route('shop.reviews.store', $product->id ) }}">
@csrf
<div class="heading">
<span> Write a review </span>
</div>
<div class="rating">
<span> {{ __('admin::app.customers.reviews.rating') }} </span>
</div>
<div class="stars">
<label class="star star-5" for="star-5" onclick="calculateRating(id)" id="1"></label>
<label class="star star-4" for="star-4" onclick="calculateRating(id)" id="2"></label>
<label class="star star-3" for="star-3" onclick="calculateRating(id)" id="3"></label>
<label class="star star-2" for="star-2" onclick="calculateRating(id)" id="4"></label>
<label class="star star-1" for="star-1" onclick="calculateRating(id)" id="5"></label>
<input type="name" name="title" class="form-control" placeholder="title">
<input type="hidden" id="rating" name="rating">
</div>
<div class="write-review">
<div class="control-group">
<label for="review">{{ __('admin::app.customers.reviews.comment') }}</label>
<textarea name="comment">
</textarea>
</div>
</div>
<div class="submit-button">
<button type="submit" class="btn btn-lg btn-primary"> SUBMIT </button>
</div>
</form>
</div>
</div>
</section>
@endsection
@push('scripts')
<script>
function calculateRating(id){
var a=document.getElementById(id);
document.getElementById("rating").value = id;
for (let i=1 ; i <= 5 ; i++){
if(id >= i){
document.getElementById(i).style.color="#242424";
}else{
document.getElementById(i).style.color="#d4d4d4";
}
}
}
</script>
@endpush

View File

@ -0,0 +1,162 @@
@inject ('reviewHelper', 'Webkul\Product\Product\Review')
@inject ('priceHelper', 'Webkul\Product\Product\Price')
@extends('shop::layouts.master')
@section('content-wrapper')
<section class="product-review">
<div class="category-breadcrumbs">
<span class="breadcrumb">Home</span> > <span class="breadcrumb">Men</span> > <span class="breadcrumb">Slit Open Jeans</span>
</div>
<div class="layouter">
<div class="mixed-group">
<div class="single-image">
<img src="{{ bagisto_asset('images/jeans_big.jpg') }}" />
</div>
<div class="details">
<div class="product-name">
{{ $product->name }}
</div>
<div class="price">
@if ($product->type == 'configurable')
<span class="main-price">${{ core()->currency($priceHelper->getMinimalPrice($product)) }}</span>
@else
@if ($priceHelper->haveSpecialPrice($product))
<span class="main-price">${{ core()->currency($priceHelper->getSpecialPrice($product)) }}</span>
@else
<span class="main-price">${{ core()->currency($product->price) }}</span>
@endif
@endif
<span class="real-price">
$25.00
</span>
<span class="discount">
10% Off
</span>
</div>
</div>
</div>
<div class="rating-reviews">
<div class="title-inline">
<span>Ratings & {{ __('admin::app.customers.reviews.name') }}</span>
<!-- <button class="btn btn-md btn-primary">Write Review</button> -->
<a href="{{ route('shop.reviews.create', $product->url_key) }}" class="btn btn-lg btn-primary right">Write Review</a>
</div>
<div class="overall">
<div class="left-side">
<span class="number">
{{ $reviewHelper->getAverageRating($product) }}
</span>
@for($i = 1; $i <= $reviewHelper->getAverageRating($product) ; $i++)
<span class="stars">
<span class="icon star-icon"></span>
</span>
@endfor
<div class="total-reviews">
{{ $reviewHelper->getTotalRating($product) }} {{ __('admin::app.customers.reviews.rating') }} & {{ $reviewHelper->getTotalReviews($product) }} {{ __('admin::app.customers.reviews.name') }}
</div>
</div>
<div class="right-side">
@foreach($reviewHelper->getPercentageRating($product) as $key=>$count)
<div class="rater 5star">
<div class="star" id={{$key}}star> Star</div>
<div class="line-bar" >
<div class="line-value" id="{{ $key }}"></div>
</div>
<div class="percentage"> {{$count}}% </div>
</div>
<br/>
@endforeach
</div>
</div>
<div class="reviews">
@foreach($reviewHelper->loadMore($product) as $review)
<div class="review">
<div class="title">
{{ $review->title }}
</div>
<div class="stars">
@for ($i = 1; $i <= $review->rating ; $i++)
<span class="icon star-icon"></span>
@endfor
</div>
<div class="message">
{{ $review->comment }}
</div>
<div class="reviewer-details">
<span class="by">
{{ __('shop::app.products.by', ['name' => $review->customer->name]) }}
</span>
<span class="when">
{{ $reviewHelper->formatDate($review->created_at) }}
</span>
</div>
</div>
@endforeach
<div class="view-all" onclick="loadMore()">Load More</div>
</div>
</div>
</div>
</section>
@endsection
@push('scripts')
<script>
window.onload = (function(){
var percentage = {};
<?php foreach ($reviewHelper->getPercentageRating($product) as $key=>$count) { ?>
percentage.<?php echo $key; ?> = <?php echo "'$count';"; ?>
<?php } ?>
var i=5;
for(var key in percentage){
width= percentage[key] * 1.58;
let id =key + 'star';
console.log(id);
document.getElementById(key).style.width = width + "px";
document.getElementById(key).style.height = 4 + "px";
document.getElementById(id).innerHTML = i + '\xa0\xa0' + "star";
i--;
}
})();
function loadMore(){
var segment_str = window.location.pathname;
var segment_array = segment_str.split( '/' );
var last_segment = segment_array[segment_array.length - 1];
url = segment_str.slice(0, segment_str.lastIndexOf('/'));
project = url + "/" + (parseInt(last_segment)+1) ;
location.href = project;
}
</script>
@endpush

View File

@ -0,0 +1 @@
wevf bebv

View File

@ -0,0 +1,65 @@
@extends('shop::layouts.master')
@section('content-wrapper')
<section class="product-detail">
<div class="category-breadcrumbs">
<span class="breadcrumb">Home</span> > <span class="breadcrumb">Men</span> > <span class="breadcrumb">Slit Open Jeans</span>
</div>
<div class="layouter">
@include ('shop::products.view.gallery')
<div class="details">
<div class="product-heading">
<span>{{ $product->name }}</span>
</div>
<div class="rating">
<img src="{{ bagisto_asset('images/5star.svg') }}" />
75 Ratings & 11 Reviews
</div>
@include ('shop::products.price', ['product' => $product])
@include ('shop::products.view.stock')
<br/>
<div class="description">
{{ $product->short_description }}
</div>
@if ($product->type == 'configurable')
@include ('shop::products.view.configurable-options')
@endif
<accordian :title="{{ __('shop::app.products.description') }}" :active="true">
<div slot="header">
{{ __('shop::app.products.description') }}
<i class="icon expand-icon right"></i>
</div>
<div slot="body">
<div class="full-description">
{{ $product->description }}
</div>
</div>
</accordian>
@include ('shop::products.view.attributes')
@include ('shop::products.view.reviews')
</div>
</div>
@include ('shop::products.view.up-sells')
</section>
@endsection

View File

@ -0,0 +1,23 @@
@inject ('productViewHelper', 'Webkul\Product\Product\View')
<accordian :title="{{ __('shop::app.products.specification') }}" :active="false">
<div slot="header">
{{ __('shop::app.products.specification') }}
<i class="icon expand-icon right"></i>
</div>
<div slot="body">
<table class="full-specifications">
@foreach ($productViewHelper->getAdditionalData($product) as $attribute)
<tr>
<td>{{ $attribute['label'] }}</td>
<td> - {{ $attribute['value'] }}</td>
</tr>
@endforeach
</table>
</div>
</accordian>

View File

@ -0,0 +1,33 @@
<div class="attributes">
<div class="attribute color">
<div class="title">Color</div>
<div class="values">
<div class="colors red"></div>
<div class="colors blue"></div>
<div class="colors green"></div>
</div>
</div>
<div class="attribute size">
<div class="title">Size</div>
<div class="values">
<div class="size xl">XL</div>
<div class="size xxl">XXL</div>
<div class="size xxxl">XXXL</div>
</div>
</div>
<div class="attribute quantity">
<div class="title">Quantity</div>
<div class="values">
<div class="size">1</div>
</div>
</div>
</div>
<hr/>

View File

@ -0,0 +1,16 @@
<div class="product-image-group">
<div class="side-group">
<img src="{{ bagisto_asset('images/jeans.jpg') }}" />
<img src="{{ bagisto_asset('images/jeans.jpg') }}" />
<img src="{{ bagisto_asset('images/jeans.jpg') }}" />
<img src="{{ bagisto_asset('images/jeans.jpg') }}" />
</div>
<div class="product-hero-image">
<img src="{{ bagisto_asset('images/jeans_big.jpg') }}" />
<img class="wishlist" src="{{ bagisto_asset('images/wish.svg') }}" />
<img class="share" src="{{ bagisto_asset('images/icon-share.svg') }}" />
</div>
</div>

View File

@ -0,0 +1,71 @@
@inject ('reviewHelper', 'Webkul\Product\Product\Review')
@if ($total = $reviewHelper->getTotalReviews($product))
<div class="rating-reviews">
<div class="title">
Ratings & Reviews
</div>
<div class="overall">
<div class="review-info">
<span class="number">
{{ $reviewHelper->getAverageRating($product) }}
</span>
<span class="stars">
@for ($i = 1; $i <= $reviewHelper->getAverageRating($product); $i++)
<span class="icon star-icon"></span>
@endfor
</span>
<div class="total-reviews">
{{ __('shop::app.products.total-reviews', ['total' => $total]) }}
</div>
</div>
<a href="{{ route('shop.reviews.create', $product->url_key) }}" class="btn btn-lg btn-primary">Write Review</a>
</div>
<div class="reviews">
@foreach ($product->reviews()->paginate(5) as $review)
<div class="review">
<div class="title">
{{ $review->title }}
</div>
<span class="stars">
@for ($i = 1; $i <= $review->rating; $i++)
<span class="icon star-icon"></span>
@endfor
</span>
<div class="message">
{{ $review->comment }}
</div>
<div class="reviewer-details">
<span class="by">
{{ __('shop::app.products.by', ['name' => $review->customer->name]) }},
</span>
<span class="when">
{{ $reviewHelper->formatDate($review->created_at) }}
</span>
</div>
</div>
@endforeach
<a href="{{ route('shop.reviews.index', $product->url_key) }}" class="view-all">View All</a>
<hr/>
</div>
</div>
@endif

View File

@ -0,0 +1,3 @@
<div class="stock-status">
InStock
</div>

View File

@ -0,0 +1,20 @@
@if ($product->up_sells()->count())
<div class="attached-products-wrapper">
<div class="title">
{{ __('shop::app.products.up-sell-title') }}
<span class="border-bottom"></span>
</div>
<div class="product-grid max-4-col">
@foreach ($product->up_sells()->paginate(4) as $up_sell_product)
@include ('shop::products.list.card', ['product' => $up_sell_product])
@endforeach
</div>
</div>
@endif

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50 (54983) - http://www.bohemiancoding.com/sketch -->
<title>Icon-Customers</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Icon-Customers" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
<g transform="translate(9.000000, 8.000000)" id="Combined-Shape" stroke="#8E8E8E" stroke-width="2">
<path d="M0.0694092808,30.8793785 C0.789639214,23.4815617 7.02613841,17.6997284 14.6130571,17.6997284 C22.1999758,17.6997284 28.436475,23.4815617 29.156705,30.8793785 L0.0694092808,30.8793785 Z M14.5,13.6997284 C10.9101491,13.6997284 8,10.7895793 8,7.19972838 C8,3.60987751 10.9101491,0.699728384 14.5,0.699728384 C18.0898509,0.699728384 21,3.60987751 21,7.19972838 C21,10.7895793 18.0898509,13.6997284 14.5,13.6997284 Z"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1271,5 +1271,312 @@ h2 {
margin-left: 31px;
}
// admin dashboard css ends here
// customer order information for admin css start here
.order-information {
.order-info {
span{
font-size: 18px;
color: #8E8E8E;
letter-spacing: -0.29px;
}
.edit {
float :right;
font-size: 16px;
color: #0041FF;
letter-spacing: -0.29px;
text-align: right;
}
}
.horizotal-rule {
width:100%;
border:1px solid #A2A2A2;
opacity: 0.2;
margin-top: 16px;
}
.order-account{
display:flex;
flex-direction: row;
margin-top: 20px;
.left-content {
width: 200px;
span {
font-size: 16px;
color: #3A3A3A;
letter-spacing: -0.26px;
}
}
.right-content {
span {
font-size: 16px;
color: #3A3A3A;
letter-spacing: -0.26px;
}
}
}
}
.account-information {
margin-top: 30px;
.account-info {
span{
font-size: 18px;
color: #8E8E8E;
letter-spacing: -0.29px;
}
.edit {
float :right;
font-size: 16px;
color: #0041FF;
letter-spacing: -0.29px;
text-align: right;
}
}
.horizotal-rule {
width:100%;
border:1px solid #A2A2A2;
opacity: 0.2;
margin-top: 16px;
}
.order-account{
display:flex;
flex-direction: row;
margin-top: 20px;
.left-content {
width: 200px;
span {
font-size: 16px;
color: #3A3A3A;
letter-spacing: -0.26px;
}
}
.right-content {
span {
font-size: 16px;
color: #3A3A3A;
letter-spacing: -0.26px;
}
.name {
color: #0041FF;
}
}
}
}
.address-information {
.address-name {
span{
font-size: 18px;
color: #8E8E8E;
letter-spacing: -0.29px;
}
.edit {
float :right;
font-size: 16px;
color: #0041FF;
letter-spacing: -0.29px;
text-align: right;
}
}
.horizotal-rule {
width:100%;
border:1px solid #A2A2A2;
opacity: 0.2;
margin-top: 16px;
}
.address-detail{
margin-top: 10px;
span {
font-size: 16px;
color: #3A3A3A;
letter-spacing: -0.26px;
display: block;
}
}
}
.address-information:last-child {
margin-top: 15px;
}
.payment-information {
.title {
span{
font-size: 18px;
color: #8E8E8E;
letter-spacing: -0.29px;
}
}
.horizotal-rule {
width:100%;
border:1px solid #A2A2A2;
opacity: 0.2;
margin-top: 16px;
}
.payment-info{
display:flex;
flex-direction: row;
margin-top: 20px;
.left-content {
width: 200px;
span {
font-size: 16px;
color: #3A3A3A;
letter-spacing: -0.26px;
}
}
.right-content {
span {
font-size: 16px;
color: #3A3A3A;
letter-spacing: -0.26px;
}
}
}
}
.payment-information:last-child {
margin-top: 25px;
}
.total {
margin-top: 2%;
height: 130px;
.calculate {
margin-right: 8%;
float: right;
.sub-total {
span {
font-size: 14px; font-size: 14px;
color: #3A3A3A;
color: #3A3A3A;
}
.left {
margin-left: 109px;
}
.middle {
margin-right: 5px;
margin-left: 5px;
}
}
.ship-handle {
margin-top: 5px;
span {
font-size: 14px;
color: #3A3A3A;
}
.left {
margin-left: 24px;
}
.middle {
margin-right: 5px;
margin-left: 5px;
}
}
.discount {
margin-top: 5px;
span {
font-size: 14px; font-size: 14px;
color: #3A3A3A;
}
.left {
margin-left: 98px;
}
.middle {
margin-right: 5px;
margin-left: 5px;
}
}
.grand-total {
margin-top: 5px;
span {
font-size: 14px; font-size: 14px;
color: #3A3A3A;
font-weight: bold;
}
.left {
margin-left: 87px;
}
.middle {
margin-right: 5px;
margin-left: 5px;
}
}
.due {
margin-top: 5px;
span {
font-size: 14px; font-size: 14px;
color: #3A3A3A;
font-weight: bold;
}
.left {
margin-left: 101px;
}
.middle {
margin-right: 5px;
margin-left: 5px;
}
}
}
}
// customer order information for admin css end here

View File

@ -18,6 +18,10 @@
@extend %menu-properties;
background-image: url("../images/Icon-Catalog.svg");
}
.customer-icon {
@extend %menu-properties;
background-image: url("../images/Icon-Customers.svg");
}
.configuration-icon {
@extend %menu-properties;
background-image: url("../images/Icon-Configure.svg");

View File

@ -106,13 +106,17 @@
<th class="grid_head" data-column-name="{{ $column->alias }}" data-column-label="{{ $column->label }}">{!! $column->sorting() !!}</th>
@endif
@endforeach
@if(isset($attribute_columns))
{{-- @if(isset($attribute_columns))
@foreach($attribute_columns as $key => $value)
<th>
{{ $value }}
<th class="grid_head"
data-column-name="{{ $attributeAliases[$key] }}"
data-column-label="{{ $attributeAliases[$key] }}"
data-column-sort="asc"
>
{{ $value }}<span class="icon sort-down-icon"></span>
</th>
@endforeach
@endif
@endif --}}
<th>
Actions
</th>
@ -131,12 +135,11 @@
@foreach ($columns as $column)
<td class="">{!! $column->render($result) !!}</td>
@endforeach
@if(isset($attribute_columns))
{{-- @if(isset($attribute_columns))
@foreach ($attribute_columns as $atc)
<td>{{ $result->{$atc} }}</td>
@endforeach
@endif
@endif --}}
<td class="action">
@foreach($actions as $action)

View File

@ -53,9 +53,13 @@ class AccountController extends Controller
'email' => 'email|unique:admins,email,' . $user->id,
'password' => 'nullable|confirmed'
]);
$user->update(request(['name', 'email', 'password']));
$data = request()->all();
if(!$data['password'])
unset($data['password']);
$user->update($data);
session()->flash('success', 'Account changes saved successfully.');

View File

@ -116,7 +116,12 @@ class UserController extends Controller
*/
public function update(UserForm $request, $id)
{
$this->admin->update(request()->all(), $id);
$data = request()->all();
if(!$data['password'])
unset($data['password']);
$this->admin->update($data, $id);
session()->flash('success', 'User updated successfully.');

View File

@ -11,11 +11,24 @@
margin-bottom: 2px;
}
.grid-view-icon {
background-image: URL("../images/icon-grid-view.svg");
width: 24px;
height: 24px;
}
.list-view-icon {
background-image: URL("../images/icon-list-view.svg");
width: 24px;
height: 24px;
}
body {
margin: 0;
padding: 0;
font-weight: 500;
font-size: 14px;
color: #242424;
font-size: 16px;
}
* {
@ -710,7 +723,7 @@ section.slider-block div.slider-content div.slider-control .light-right-icon {
.layered-filter-wrapper {
width: 25%;
float: left;
margin-right: 20px;
padding-right: 20px;
min-height: 1px;
}
@ -802,6 +815,11 @@ section.slider-block div.slider-content div.slider-control .light-right-icon {
width: 100%;
}
.main-container-wrapper .main {
display: inline-block;
width: 75%;
}
.main-container-wrapper .product-grid {
display: grid;
grid-gap: 30px;
@ -832,49 +850,36 @@ section.slider-block div.slider-content div.slider-control .light-right-icon {
justify-content: center;
}
.main-container-wrapper .product-grid .product-card .product-image img {
.main-container-wrapper .product-card .product-image img {
-ms-flex-item-align: center;
align-self: center;
width: 100%;
margin-bottom: 14px;
}
.main-container-wrapper .product-grid .product-card .product-name {
.main-container-wrapper .product-card .product-name {
font-size: 16px;
margin-bottom: 14px;
width: 100%;
color: #242424;
}
.main-container-wrapper .product-grid .product-card .product-price {
.main-container-wrapper .product-card .product-name a {
color: #242424;
}
.main-container-wrapper .product-card .product-description {
font-size: 16px;
margin-bottom: 14px;
width: 100%;
font-weight: 600;
display: none;
}
.main-container-wrapper .product-grid .product-card .product-price .price-label {
font-size: 14px;
font-weight: 400;
}
.main-container-wrapper .product-grid .product-card .product-price .regular-price {
font-size: 16px;
color: #A5A5A5;
text-decoration: line-through;
margin-right: 10px;
}
.main-container-wrapper .product-grid .product-card .product-price .special-price {
font-size: 16px;
color: #FF6472;
}
.main-container-wrapper .product-grid .product-card .product-ratings {
.main-container-wrapper .product-card .product-ratings {
width: 100%;
margin-bottom: 14px;
}
.main-container-wrapper .product-grid .product-card .cart-fav-seg {
.main-container-wrapper .product-card .cart-fav-seg {
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
@ -884,12 +889,91 @@ section.slider-block div.slider-content div.slider-control .light-right-icon {
align-items: center;
}
.main-container-wrapper .product-grid .product-card .cart-fav-seg .addtocart {
.main-container-wrapper .product-card .cart-fav-seg .addtocart {
border-radius: 0px;
margin-right: 10px;
text-transform: uppercase;
}
.main-container-wrapper .product-list .product-card {
width: 100%;
display: inline-block;
margin-bottom: 20px;
}
.main-container-wrapper .product-list .product-card .product-image {
float: left;
width: 30%;
height: 350px;
}
.main-container-wrapper .product-list .product-card .product-image img {
height: 100%;
}
.main-container-wrapper .product-list .product-card .product-information {
float: right;
width: 70%;
padding-left: 30px;
}
.main-container-wrapper .product-list .product-card:last-child {
margin-bottom: 0;
}
.main-container-wrapper .top-toolbar {
width: 100%;
display: inline-block;
margin-bottom: 25px;
}
.main-container-wrapper .top-toolbar .page-info {
float: left;
color: #242424;
line-height: 45px;
}
.main-container-wrapper .top-toolbar .pager {
float: right;
}
.main-container-wrapper .top-toolbar .pager label {
font-size: 16px;
margin-right: 5px;
}
.main-container-wrapper .top-toolbar .pager select {
background: #FFFFFF;
border: 1px solid #C7C7C7;
border-radius: 3px;
font-size: 16px;
color: #242424;
padding: 10px;
}
.main-container-wrapper .top-toolbar .pager .view-mode {
display: inline-block;
margin-right: 20px;
}
.main-container-wrapper .top-toolbar .pager .view-mode a, .main-container-wrapper .top-toolbar .pager .view-mode span {
display: inline-block;
vertical-align: middle;
}
.main-container-wrapper .top-toolbar .pager .view-mode a.grid-view, .main-container-wrapper .top-toolbar .pager .view-mode span.grid-view {
margin-right: 10px;
}
.main-container-wrapper .top-toolbar .pager .sorter {
display: inline-block;
margin-right: 10px;
}
.main-container-wrapper .top-toolbar .pager .limiter {
display: inline-block;
}
.main-container-wrapper .bottom-toolbar {
display: block;
margin-top: 40px;
@ -971,6 +1055,30 @@ section.slider-block div.slider-content div.slider-control .light-right-icon {
width: 100%;
}
.product-price {
font-size: 16px;
margin-bottom: 14px;
width: 100%;
font-weight: 600;
}
.product-price .price-label {
font-size: 14px;
font-weight: 400;
}
.product-price .regular-price {
font-size: 16px;
color: #A5A5A5;
text-decoration: line-through;
margin-right: 10px;
}
.product-price .special-price {
font-size: 16px;
color: #FF6472;
}
.footer {
background-color: #f2f2f2;
padding-left: 10%;
@ -1293,23 +1401,14 @@ section.product-detail div.layouter .mixed-group .details .product-name, section
margin-bottom: 20px;
}
section.product-detail div.layouter .mixed-group .details .price, section.product-review div.layouter .mixed-group .details .price {
section.product-detail div.layouter .mixed-group .details .product-price, section.product-review div.layouter .mixed-group .details .product-price {
margin-bottom: 14px;
}
section.product-detail div.layouter .mixed-group .details .price .main-price, section.product-review div.layouter .mixed-group .details .price .main-price {
font-size: 24px;
color: #FF6472;
}
section.product-detail div.layouter .mixed-group .details .price .real-price, section.product-review div.layouter .mixed-group .details .price .real-price {
color: #A5A5A5;
-webkit-text-decoration-line: line-through;
text-decoration-line: line-through;
}
section.product-detail div.layouter .rating-reviews, section.product-review div.layouter .rating-reviews {
margin-top: 30px;
margin-top: 0px;
width: 50%;
margin-left: 20px;
}
section.product-detail div.layouter .rating-reviews .title-inline, section.product-review div.layouter .rating-reviews .title-inline {
@ -1384,8 +1483,6 @@ section.product-detail div.layouter .rating-reviews .overall .right-side .rater
}
section.product-detail div.layouter .rating-reviews .overall .right-side .rater .line-bar .line-value, section.product-review div.layouter .rating-reviews .overall .right-side .rater .line-bar .line-value {
height: 4px;
width: 100px;
background-color: #0031F0;
}
@ -1469,13 +1566,13 @@ section.product-detail div.layouter .details .rating, section.product-review div
margin-bottom: 14px;
}
section.product-detail div.layouter .details .price, section.product-review div.layouter .details .price {
section.product-detail div.layouter .details .product-price, section.product-review div.layouter .details .product-price {
margin-bottom: 14px;
font-size: 24px;
}
section.product-detail div.layouter .details .price .main-price, section.product-review div.layouter .details .price .main-price {
section.product-detail div.layouter .details .product-price .special-price, section.product-review div.layouter .details .product-price .special-price {
font-size: 24px;
color: #FF6472;
}
section.product-detail div.layouter .details .stock-status, section.product-review div.layouter .details .stock-status {
@ -1486,9 +1583,19 @@ section.product-detail div.layouter .details .description, section.product-revie
margin-bottom: 14px;
}
section.product-detail div.layouter .details hr, section.product-review div.layouter .details hr {
border-top: 1px solid #E8E8E8;
margin-bottom: 17px;
section.product-detail div.layouter .details .full-specifications td, section.product-review div.layouter .details .full-specifications td {
padding: 10px 0;
color: #5E5E5E;
}
section.product-detail div.layouter .details .full-specifications td:first-child, section.product-review div.layouter .details .full-specifications td:first-child {
padding-right: 40px;
}
section.product-detail div.layouter .details .accordian .accordian-header, section.product-review div.layouter .details .accordian .accordian-header {
font-size: 16px;
padding-left: 0;
font-weight: 600;
}
section.product-detail div.layouter .details .attributes, section.product-review div.layouter .details .attributes {
@ -1576,13 +1683,14 @@ section.product-detail div.layouter .details .rating-reviews, section.product-re
section.product-detail div.layouter .details .rating-reviews .title, section.product-review div.layouter .details .rating-reviews .title {
margin-bottom: 15px;
font-weight: 600;
}
section.product-detail div.layouter .details .rating-reviews .overall, section.product-review div.layouter .details .rating-reviews .overall {
margin-bottom: 5px;
}
section.product-detail div.layouter .details .rating-reviews .overall .number, section.product-review div.layouter .details .rating-reviews .overall .number {
section.product-detail div.layouter .details .rating-reviews .overall .review-info .number, section.product-review div.layouter .details .rating-reviews .overall .review-info .number {
font-size: 34px;
}
@ -1602,12 +1710,22 @@ section.product-detail div.layouter .details .rating-reviews .reviews .review, s
section.product-detail div.layouter .details .rating-reviews .reviews .review .stars, section.product-review div.layouter .details .rating-reviews .reviews .review .stars {
margin-bottom: 15px;
display: inline-block;
}
section.product-detail div.layouter .details .rating-reviews .reviews .review .stars .icon, section.product-review div.layouter .details .rating-reviews .reviews .review .stars .icon {
width: 18px;
height: 18px;
}
section.product-detail div.layouter .details .rating-reviews .reviews .review .message, section.product-review div.layouter .details .rating-reviews .reviews .review .message {
margin-bottom: 10px;
}
section.product-detail div.layouter .details .rating-reviews .reviews .review .reviewer-details, section.product-review div.layouter .details .rating-reviews .reviews .review .reviewer-details {
color: #5E5E5E;
}
section.product-detail div.layouter .details .rating-reviews .reviews .view-all, section.product-review div.layouter .details .rating-reviews .reviews .view-all {
margin-top: 15px;
color: #0031f0;
@ -1847,18 +1965,29 @@ section.cart .cart-content .right-side .coupon-section .after-coupon-amount .amo
font-weight: bold;
}
.related-products-wrapper {
.attached-products-wrapper {
margin-bottom: 80px;
}
.related-products-wrapper .title {
margin-bottom: 22px;
.attached-products-wrapper .title {
margin-bottom: 40px;
font-size: 18px;
color: #242424;
text-align: center;
position: relative;
}
.related-products-wrapper .horizontal-rule {
.attached-products-wrapper .title .border-bottom {
border-bottom: 1px solid rgba(162, 162, 162, 0.2);
display: inline-block;
width: 100px;
position: absolute;
top: 40px;
left: 50%;
margin-left: -50px;
}
.attached-products-wrapper .horizontal-rule {
height: 1px;
background: #E8E8E8;
width: 148px;
@ -1867,12 +1996,6 @@ section.cart .cart-content .right-side .coupon-section .after-coupon-amount .amo
margin-right: auto;
}
.related-products-wrapper .related-products {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
grid-gap: 10px;
}
.order {
margin-left: 5.5%;
margin-top: 1%;
@ -3543,3 +3666,175 @@ section.cart .cart-content .right-side .coupon-section .after-coupon-amount .amo
text-align: center;
border: none;
}
section.review {
font-size: 16px;
color: #242424;
}
section.review .category-breadcrumbs {
display: inline;
}
section.review .review-layouter {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-flow: row;
flex-flow: row;
margin-top: 20px;
}
section.review .review-layouter .product-info .image {
border: 1px solid red;
}
section.review .review-layouter .product-info .image img {
height: 280px;
width: 280px;
}
section.review .review-layouter .product-info .heading {
margin-top: 20px;
}
section.review .review-layouter .product-info .heading span {
font-size: 24px;
color: #242424;
letter-spacing: -0.58px;
}
section.review .review-layouter .product-info .price {
margin-top: 10px;
}
section.review .review-layouter .product-info .price .pro-price {
font-size: 24px;
color: #FF6472;
letter-spacing: -0.58px;
}
section.review .review-layouter .product-info .price .pro-price-not {
margin-left: 10px;
font-size: 16px;
color: #A5A5A5;
letter-spacing: -0.26px;
}
section.review .review-layouter .product-info .price .offer {
margin-left: 10px;
font-size: 16px;
color: #242424;
letter-spacing: -0.26px;
}
section.review .review-layouter .review-info {
margin-left: 20px;
width: 49%;
}
section.review .review-layouter .review-info .heading {
margin-top: 10px;
}
section.review .review-layouter .review-info .heading span {
font-size: 16px;
color: #242424;
letter-spacing: -0.26px;
}
section.review .review-layouter .review-info .heading .btn.btn-primary.right {
float: right;
margin-top: -10px;
}
section.review .review-layouter .review-info .rating {
margin-top: 25px;
font-size: 16px;
color: #5E5E5E;
letter-spacing: -0.12px;
}
section.review .review-layouter .review-info .rating span {
display: inline;
}
section.review .review-layouter .review-info .stars {
width: 270px;
display: inline-block;
}
section.review .review-layouter .review-info .stars label.star {
font-size: 36px;
color: #d4d4d4;
-webkit-transition: all .2s;
transition: all .2s;
}
section.review .review-layouter .review-info .stars label.star:before {
content: '\2605';
}
section.review .review-layouter .review-info .write-review {
margin-top: 25px;
}
section.review .review-layouter .review-info .write-review .control-group {
margin-bottom: 0px;
}
section.review .review-layouter .review-info .write-review .control-group textarea {
margin-top: 5px;
border: 2px solid #C7C7C7;
border-radius: 3px;
width: 600px;
height: 120px;
}
section.review .review-layouter .review-info .submit-button {
margin-top: 10px;
}
section.review .review-layouter .review-info .submit-button button {
background: #0031F0;
font-size: 14px;
color: #FFFFFF;
letter-spacing: -0.26px;
text-align: center;
width: 120px;
height: 38px;
border: none;
}
section.review .review-layouter .review-info .review-detail {
height: 150px;
border: 1px solid firebrick;
margin-top: 30px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
}
section.review .review-layouter .review-info .review-detail .rating-review {
margin-top: 40px;
margin-left: 20px;
width: 48%;
}
section.review .review-layouter .review-info .review-detail .rating-review .avg-rating-count span {
font-size: 34px;
color: #242424;
letter-spacing: -0.82px;
text-align: center;
}
section.review .review-layouter .review-info .review-detail .rating-calculate .progress-only {
width: 20px;
border: 1px solid blue;
}