Synchro back-office, fix on tariffs

This commit is contained in:
Ludovic CANDELLIER
2021-10-26 21:41:46 +02:00
parent c150be2c3e
commit 86f6ee9a13
45 changed files with 1095 additions and 406 deletions

View File

@@ -14,6 +14,19 @@ var jsCompat = [
'node_modules/es6-promise/dist/es6-promise.min.js',
]
var jsSite = [
jsBase,
jsBootstrap,
'build/js/site.js',
]
var cssSite = [
'node_modules/bootstrap/dist/css/bootstrap.min.css',
'node_modules/@fortawesome/fontawesome-free/css/all.min.css',
'node_modules/animate.css/animate.min.css',
'build/css/site.css',
]
var jsAdminLTE = [
jsBase,
jsBootstrap,
@@ -88,7 +101,7 @@ var jsMain = [
var cssPrint = [
// 'node_modules/bootstrap/dist/css/bootstrap.min.css',
'node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css',
'cssIcons',
'build/print.css'
]
@@ -179,7 +192,8 @@ module.exports = function(grunt) {
'public/assets/js/main.min.js': jsMain,
'public/assets/css/main.min.css': cssMain,
'public/assets/plugins/datatables.min.js': jsDataTables,
'public/assets/plugins/adminlte/adminlte.min.js': jsAdminLTE
'public/assets/plugins/adminlte/adminlte.min.js': jsAdminLTE,
'public/js/site.min.js': jsSite,
},
]
},
@@ -194,6 +208,14 @@ module.exports = function(grunt) {
options: {
separator: '\n'
},
sitecss: {
src: cssSite,
dest: 'public/css/site.min.css'
},
siteJs: {
src: jsSite,
dest: 'public/js/site.min.js'
},
mainjs: {
src: jsMain,
dest: 'public/assets/js/main.min.js'
@@ -232,6 +254,9 @@ module.exports = function(grunt) {
{
'public/assets/css/print.min.css': cssPrint
},
{
'public/css/site.min.css': cssSite
},
]
}
},
@@ -242,13 +267,13 @@ module.exports = function(grunt) {
expand: true,
cwd: 'node_modules/@fortawesome/fontawesome-free/webfonts/',
src: ['**'],
dest: 'public/assets/fonts/'
dest: 'public/webfonts/'
},
{
expand: true,
cwd: 'build/fonts',
src: ['**'],
dest: 'public/assets/fonts/'
dest: 'public/webfonts/'
},
{
expand: true,

View File

@@ -0,0 +1,15 @@
<?php
namespace BeyondCode\Comments\Contracts;
interface Commentator
{
/**
* Check if a comment for a specific model needs to be approved.
* @param mixed $model
* @return bool
*/
public function needsCommentApproval($model): bool;
}

View File

@@ -5,7 +5,7 @@ namespace App\Datatables\Admin\Core;
use Yajra\DataTables\Html\Column;
use App\Datatables\ParentDataTable as DataTable;
use App\Models\Admin\Core\Comment;
use App\Models\Core\Comment;
use App\Repositories\Core\Comments;
class CommentsDataTable extends DataTable

View File

@@ -6,15 +6,16 @@ use Yajra\DataTables\Html\Column;
use App\Datatables\ParentDataTable as DataTable;
use App\Models\Shop\Article;
use App\Repositories\Shop\Articles;
class ArticlesDataTable extends DataTable
{
public $model_name = 'articles';
public $sortedColumn = 1;
public $sortedColumn = 2;
public function query(Article $model)
{
$model = $model::with('article_nature')->withCount(['categories', 'tags'])->joinRelationship('article_nature');
$model = $model::with(['article_nature','image'])->withCount(['categories', 'tags'])->joinRelationship('article_nature');
$model = self::filterByArticleNature($model);
return self::buildQuery($model);
}
@@ -25,10 +26,22 @@ class ArticlesDataTable extends DataTable
return $article_nature_id ? $model->byArticleNature($article_nature_id) : $model;
}
public function modifier($datatables)
{
$datatables
->editColumn('thumb', function (Article $article) {
return Articles::getThumbsSrc($article->image);
})
->rawColumns(['thumb','action']);
return parent::modifier($datatables);
}
protected function getColumns()
{
return [
Column::make('article_nature.name')->title('Nature'),
Column::make('thumb')->searchable(false),
Column::make('name')->title('Nom'),
Column::make('tags_count')->title('Tags')->class('text-right')->searchable(false),
Column::make('categories_count')->title('Rayons')->class('text-right')->searchable(false),

View File

@@ -7,7 +7,15 @@ use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
use App\Repositories\Shop\Categories;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public static function init()
{
$data['categories'] = Categories::getTree();
return $data;
}
}

View File

@@ -6,11 +6,11 @@ use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Repositories\Shop\Categories;
use App\Datatables\Shop\CategoriesDataTable;
use App\Repositories\Shop\Offers;
class CategoryController extends Controller
{
public function index(CategoriesDataTable $dataTable)
public function index()
{
return $dataTable->render('Shop.Categories.list');
}
@@ -22,8 +22,10 @@ class CategoryController extends Controller
public function show($id)
{
$data = Categories::get($id);
return view('Shop.Categories.view', $data);
$data = self::init();
$data['category'] = Categories::getByCategory($id)->toArray();
$data['offers'] = Offers::getByCategory($id)->toArray();
return view('Shop.shelve', $data);
}
public function getTree()

View File

@@ -7,30 +7,19 @@ use App\Http\Controllers\Controller;
use App\Repositories\Shop\Articles;
use App\Repositories\Shop\Categories;
use App\Repositories\Shop\Offers;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
// $this->middleware('auth');
}
/**
* Show the application dashboard.
*
* @return \Illuminate\Contracts\Support\Renderable
*/
public function index()
{
$data['categories'] = Categories::getTree();
$data['category'] = Categories::get(15)->toArray();
$data['articles'] = Articles::getByCategory(0)->toArray();
// dump($data);
$data = self::init();
$data['offers'] = Offers::getLast()->toArray();
return view('Shop.home', $data);
}
}

View File

@@ -2,22 +2,68 @@
namespace App\Models\Core;
use Exception;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Repositories\Core\DateTime;
use App\Traits\HasComments;
class Comment extends Model
{
protected $guarded = [];
use HasComments;
public function user()
protected $fillable = [
'comment',
'user_id',
'is_approved'
];
protected $casts = [
'is_approved' => 'boolean'
];
public function scopeApproved($query)
{
return $this->belongsTo(\App\Models\Core\Auth\User::class);
return $query->where('is_approved', true);
}
public function getUpdatedAtAttribute($value)
public function commentable()
{
return DateTime::DateToLocale($value);
return $this->morphTo();
}
public function commentator()
{
return $this->belongsTo($this->getAuthModelName(), 'user_id');
}
public function approve()
{
$this->update([
'is_approved' => true,
]);
return $this;
}
public function disapprove()
{
$this->update([
'is_approved' => false,
]);
return $this;
}
protected function getAuthModelName()
{
if (config('comments.user_model')) {
return config('comments.user_model');
}
if (!is_null(config('auth.providers.users.model'))) {
return config('auth.providers.users.model');
}
throw new Exception('Could not determine the commentator model name.');
}
}

View File

@@ -10,13 +10,14 @@ use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
use BeyondCode\Comments\Traits\HasComments;
use Rinvex\Categories\Traits\Categorizable;
use Rinvex\Tags\Traits\Taggable;
use Kirschbaum\PowerJoins\PowerJoins;
use Fico7489\Laravel\EloquentJoin\Traits\EloquentJoin;
use Wildside\Userstamps\Userstamps;
use App\Traits\HasComments;
class Article extends Model implements HasMedia
{
use Categorizable, EloquentJoin, HasComments, InteractsWithMedia, Powerjoins, Taggable, SoftDeletes, UserStamps;
@@ -44,6 +45,11 @@ class Article extends Model implements HasMedia
return $this->hasMany(InvoiceItem::class);
}
public function offers()
{
return $this->hasMany(Offer::class);
}
public function prices()
{
return $this->hasMany(Price::class);
@@ -66,6 +72,9 @@ class Article extends Model implements HasMedia
public function scopeByCategory($query, $category_id)
{
return $query->whereHas('categories', function ($query) use ($category_id) {
$query->where('id', $category_id);
});
}
public function scopeByArticleNature($query, $id)
@@ -83,6 +92,11 @@ class Article extends Model implements HasMedia
return $query->where($this->table . '.product_id', $model_id);
}
public function scopeWithOffers($query)
{
return $query->has('Offers');
}
public function registerMediaConversions(Media $media = null) : void
{
$this->addMediaConversion('thumb')->fit(Manipulations::FIT_CROP, 32, 32);

View File

@@ -35,4 +35,9 @@ class Category extends Model
return $this->belongsTo(app('rinvex.categories.category'),'category_id');
}
public function scopeByCategory($query, $category_id)
{
return $query->where('category_id', $category_id);
}
}

View File

@@ -4,7 +4,8 @@ namespace App\Models\Shop;
use Illuminate\Database\Eloquent\Model;
use BeyondCode\Comments\Traits\HasComments;
use App\Traits\HasComments;
class Offer extends Model
{
use HasComments;
@@ -17,6 +18,11 @@ class Offer extends Model
return $this->belongsTo(Article::class);
}
public function categories()
{
return $this->article->categories();
}
public function variation()
{
return $this->belongsTo(Variation::class);
@@ -26,4 +32,26 @@ class Offer extends Model
{
return $this->belongsTo(Tariff::class);
}
public function scopeByArticle($query, $id)
{
return $query->where('article_id', $id);
}
public function scopeByCategory($query, $category_id)
{
return $query->whereHas('article.categories', function ($query) use ($category_id) {
$query->where('category_id', $category_id);
});
}
public function scopeByStatus($query, $id)
{
return $query->where('status_id', $id);
}
public function scopeByVariation($query, $id)
{
return $query->where('variation_id', $id);
}
}

View File

@@ -4,9 +4,10 @@ namespace App\Models\Shop;
use Illuminate\Database\Eloquent\Model;
use BeyondCode\Comments\Traits\HasComments;
use Znck\Eloquent\Traits\BelongsToThrough;
use App\Traits\HasComments;
class PriceList extends Model
{
use BelongsToThrough, HasComments;

View File

@@ -5,9 +5,10 @@ namespace App\Models\Shop;
use Illuminate\Database\Eloquent\Model;
use Staudenmeir\EloquentHasManyDeep\HasRelationships;
use BeyondCode\Comments\Traits\HasComments;
use Kirschbaum\PowerJoins\PowerJoins;
use App\Traits\HasComments;
class Tariff extends Model
{
use HasComments, HasRelationships, PowerJoins;

View File

@@ -4,7 +4,7 @@ namespace App\Models\Shop;
use Illuminate\Database\Eloquent\Model;
use BeyondCode\Comments\Traits\HasComments;
use App\Traits\HasComments;
class Variation extends Model
{
use HasComments;

View File

@@ -52,7 +52,7 @@ class Species
public static function get($id)
{
return Specie::findOrFail($id);
return Specie::with('tags.group')->findOrFail($id);
}
public static function storeFull($data)

View File

@@ -46,7 +46,7 @@ class Varieties
public static function get($id)
{
return Variety::findOrFail($id);
return Variety::with('tags.group')->findOrFail($id);
}
public static function getFull($id)

View File

@@ -1,26 +0,0 @@
<?php
namespace App\Repositories\Core\Auth;
use App\Models\Core\Auth\UserStatusTeam;
class UserStatusTeams
{
// supprime l'association entre les équipes et le statut utilisateur donné
public function delete_teams($id)
{
return UserStatusTeam::byUserStatus($id)->delete();
}
// associe une équipe avec un statut utilisateur
public function insert_team($user_status_id, $team_id)
{
return UserStatusTeam::create(['team_id' => $team_id, 'user_status_id' => $user_status_id]);
}
// récupère les équipes d'un statut utilisateur donné
public function select_teams_by_id($id)
{
return UserStatusTeam::select('team_id')->byUserStatus($id)->get();
}
}

View File

@@ -1,100 +0,0 @@
<?php
namespace App\Repositories\Core\Auth;
use App\Models\Core\Auth\UserStatus;
class UserStatuses
{
// compte le nombre de statut utilisateur
public static function count()
{
return UserStatus::count();
}
// supprime un statut utilisateur
public static function delete($id)
{
return UserStatus::destroy($id);
}
// ajoute un statut utilisateur
public static function insert($name, $translated, $negociator)
{
return UserStatus::create(['name' => $name, 'translated' => $translated, 'negociator' => $negociator]);
}
// reset le négociateur parmi les statuts
public static function reset_negociator_status()
{
return UserStatus::update(['negociator' => null]);
}
// récupère toutes les infos sur les statuts utilisateur
public static function select_all()
{
return UserStatus::all()->toArray();
}
// récupère les infos pour un statut utilisateur donné
public static function select_by_id($id)
{
return UserStatus::find($id)->toArray();
}
// récupère les infos pour un statut utilisateur donné
public static function select_by_name($name)
{
return UserStatus::byName($name)->first()->toArray();
}
// récupère les infos du statut considéré comme négociant d'un contrat
public static function select_by_negociator()
{
$status = UserStatus::byNegociator()->first();
return $status ? $status->toArray() : null;
}
// met à jour le statut actif/inactif d'un statut utilisateur
public static function toggle_active($id, $active)
{
return UserStatus::find($id)->update(['active' => $active]);
}
// met à jour les informations d'un statut utilisateur
public static function update($id, $name, $translated, $negociator)
{
return UserStatus::find($id)->update(['id' => $id, 'name' => $name, 'translated' => $translated, 'negociator' => $negociator]);
}
// met à jour les informations d'un statut utilisateur
public static function update_negociator($id, $negociator)
{
return UserStatus::find($id)->update(['negociator' => $negociator]);
}
public static function getAllUserStatuses($input)
{
$data = [];
$statuses = self::select_all();
foreach ($statuses as $status) {
if ($status['active'] <= 0) {
continue;
}
$item = array();
$item['id'] = $status['id'];
$item['name'] = \App\Repositories\Translate::translateClient($status['translated']);
array_push($data, $item);
}
$data = \App\Repositories\Functions::array_orderby($data, 'name', SORT_ASC);
return $data;
}
public static function getOptions()
{
return UserStatus::orderBy('name', 'asc')->get()->pluck('name', 'id')->toArray();
}
public static function getNegociatorsOptions()
{
}
}

View File

@@ -36,7 +36,7 @@ class DateTime
if (!is_null($date) && !empty($date)) {
$date = Carbon::parse($date)->format($format);
} elseif ($date == 'now') {
$date = Carbon::now()->format($format);
$date = today()->format($format);
}
return $date;
}
@@ -47,7 +47,7 @@ class DateTime
if (!is_null($date) && !empty($date)) {
$date = Carbon::parse($date)->format($format);
} elseif ($date == 'now') {
$date = Carbon::now()->format($format);
$date = now()->format($format);
}
return $date;
}
@@ -76,6 +76,9 @@ class DateTime
public static function convertTime($date)
{
$format = self::getLocaleFormatDatetime();
if (strlen($date) == 16) {
$date .= ':00';
}
return !empty($date) ? Carbon::createFromFormat($format, $date)->isoFormat('Y-MM-DD HH:mm:ss') : null;
}
@@ -102,12 +105,12 @@ class DateTime
{
$locale = self::getLang();
switch ($locale) {
case 'fr':
case 'en':
$format = 'd/m/Y';
break;
default:
$format = 'Y-m-d';
case 'fr':
case 'en':
$format = 'd/m/Y';
break;
default:
$format = 'Y-m-d';
}
return $format;
}
@@ -116,29 +119,45 @@ class DateTime
{
$locale = self::getLang();
switch ($locale) {
case 'fr':
case 'en':
$format = 'd/m/Y H:i:s';
break;
default:
$format = 'Y-m-d H:i:s';
case 'fr':
case 'en':
$format = 'd/m/Y H:i:s';
break;
default:
$format = 'Y-m-d H:i:s';
}
return $format;
}
public static function getLocaleDateFull($date)
public static function getLocaleDateFull($date = false)
{
return Carbon::parse($date)->isoFormat('LLLL');
return self::getISOFormat('LL', $date);
}
public static function getLocaleDateFullShort($date)
public static function getLocaleDateTimeFull($date = false)
{
return Carbon::parse($date)->isoFormat('lll');
return self::getISOFormat('LLL', $date);
}
public static function getLocaleHour($date)
public static function getLocaleDateFullShort($date = false)
{
return Carbon::parse($date)->isoFormat('');
return self::getISOFormat('ll', $date);
}
public static function getLocaleDateTimeFullShort($date = false)
{
return self::getISOFormat('lll', $date);
}
public static function getLocaleTime($date = false)
{
return self::getISOFormat('LT', $date);
}
public static function getISOFormat($format, $date = false)
{
$date = $date ? $date : now();
return Carbon::parse($date)->isoFormat($format);
}
public static function relativeTime()

View File

@@ -1,55 +0,0 @@
<?php
namespace App\Repositories\Core;
class Media
{
public static function getImages($model)
{
if (!$model) {
return false;
}
$model->getMedia();
foreach ($model->media as $key => $media) {
$model->media[$key]['url'] = $media->getUrl();
}
return $model->media;
}
public static function storeImages($model, $files)
{
if ($files) {
foreach ($files as $file) {
self::storeImage($model, $file);
}
}
}
public static function storeImage($model, $file)
{
return $model->addMedia($file)->toMediaCollection('images');
}
public static function deleteImage($model, $index)
{
$model->getMedia();
$ret = $model->media[$index]->delete();
return "1";
}
public static function getThumbSrc($image)
{
if (!$image) {
return null;
}
$id = $image['id'];
$images = json_decode($image['responsive_images'], true);
/*
$urls = $images['medialibrary_original']['urls'];
$img = $urls[count($urls)-1];
$src = "storage/$id/responsive-images/$img";
*/
return $src ?? null;
}
}

View File

@@ -0,0 +1,99 @@
<?php
namespace App\Repositories\Core;
class Medias
{
public static function getImage($model, $conversion = 'normal', $collection = 'images')
{
$img = $model->getMedia($collection)->first();
return $img ? $img->getUrl($conversion) : false;
}
public static function getImages($model)
{
if (!$model) {
return false;
}
$model->getMedia();
foreach ($model->media as $key => $media) {
$model->media[$key]['url'] = $media->getUrl();
}
return $model->media;
}
public static function storeImages($model, $files)
{
if ($files) {
foreach ($files as $file) {
self::storeImage($model, $file);
}
}
}
public static function storeImage($model, $file, $collection = 'images')
{
return $model->addMedia($file)->sanitizingFileName(function ($fileName) {
return str_replace(['#', '/', '\\', ' '], '-', $fileName);
})->toMediaCollection($collection);
}
public static function deleteImages($model, $collection = 'images')
{
$ret = $model->clearMediaCollection($collection);
return true;
}
public static function deleteImage($model, $index)
{
$model->getMedia();
$ret = $model->media[$index]->delete();
return true;
}
public static function buildURL($image, $conversion = '')
{
return self::getPath($image) . self::getConversion($image, $conversion);
}
public static function getPath($image)
{
$model = basename(str_replace('\\', '/', $image->model_type));
return '/storage/' . $model . '/' . $image->collection_name . '/' . $image->id;
}
public static function getConversion($image, $conversion = '')
{
// return $conversion ? '/conversions/' . $image->name . '-' . $conversion . self::getExtension($image->file_name) : $image->file_name;
return $conversion ? '/conversions/' . $image->name . '-' . $conversion . '.jpg' : $image->file_name;
}
public static function getExtension($filename)
{
return '.' . pathinfo($filename, PATHINFO_EXTENSION);
}
public static function getThumbSrc($image)
{
if (!$image) {
return null;
}
$id = $image['id'];
$filename = $image['name'] . '-thumb' . self::getExtension($image['file_name']);
return "/storage/$id/conversions/$filename";
}
public static function getPreviewSrc($image)
{
if (!$image) {
return null;
}
$id = $image['id'];
$filename = $image['name'] . '-preview' . self::getExtension($image['file_name']);
return "/storage/$id/conversions/$filename";
}
}

View File

@@ -5,7 +5,7 @@ namespace App\Repositories\Shop;
use Illuminate\Support\Str;
use App\Repositories\Core\Tag;
use App\Repositories\Core\Media;
use App\Repositories\Core\Medias;
use App\Repositories\Core\Comments;
use App\Repositories\Botanic\Species;
use App\Repositories\Botanic\Varieties;
@@ -74,7 +74,7 @@ class Articles
public static function getInherited($id)
{
$article = Article::with('product.tags')->findOrFail($id);
$article = Article::with('product.tags.group')->findOrFail($id);
$product_type = $article->product_type;
switch ($product_type) {
case 'App\Models\Botanic\Variety':
@@ -245,26 +245,31 @@ class Articles
public static function storeImages($article, $files)
{
return Media::storeImages($article, $files);
return Medias::storeImages($article, $files);
}
public static function storeImage($article, $file)
{
return Media::storeImage($article, $file);
return Medias::storeImage($article, $file);
}
public static function getImages($id)
{
return Media::getImages(self::get($id));
return Medias::getImages(self::get($id));
}
public static function getThumbSrc($image)
{
return Media::getThumbSrc($image);
return Medias::getThumbSrc($image);
}
public static function getPreviewSrc($image)
{
return Medias::getPreviewSrc($image);
}
public static function deleteImage($id, $index)
{
return Media::deleteImage(self::get($id), $index);
return Medias::deleteImage(self::get($id), $index);
}
}

View File

@@ -16,6 +16,11 @@ class Categories
return Category::with('CategoryTree')->find($id);
}
public static function getByCategory($category_id)
{
return Category::byCategory($category_id)->first();
}
public static function getTree()
{
return CategoryTrees::getTree();

View File

@@ -6,14 +6,15 @@ use App\Models\Shop\Offer;
class Offers
{
public static function getOptions()
public static function getLast()
{
return Offer::orderBy('value', 'asc')->get()->pluck('value', 'id')->toArray();
return Offer::with(['article.image'])->orderByDesc('updated_at')->get();
}
public static function getOptionsByPackage($package_id)
public static function getByCategory($category_id)
{
return Offer::byPackage($package_id)->orderBy('value', 'asc')->get()->pluck('value', 'id')->toArray();
return Offer::with(['article.image'])->byCategory($category_id)->get();
}
public static function getAll()

View File

@@ -29,6 +29,12 @@ class Tags
return Tag::orderBy('order', 'asc')->get();
}
public static function getFullname($id)
{
$tag = Tag::with('group')->find($id);
return $tag->group->name . '-' . $tag->name;
}
public static function get($id)
{
return Tag::find($id);

11
app/Traits/CanComment.php Normal file
View File

@@ -0,0 +1,11 @@
<?php
namespace App\Traits;
trait CanComment
{
public function needsCommentApproval($model): bool
{
return true;
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Model;
use App\Contracts\Commentator;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use App\Models\Core\Comment;
trait HasComments
{
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
public function comment(string $comment)
{
return $this->commentAsUser(auth()->user(), $comment);
}
public function commentAsUser(?Model $user, string $comment)
{
$comment = new Comment([
'comment' => $comment,
'is_approved' => ($user instanceof Commentator) ? ! $user->needsCommentApproval($this) : false,
'user_id' => is_null($user) ? null : $user->getKey(),
'commentable_id' => $this->getKey(),
'commentable_type' => get_class(),
]);
return $this->comments()->save($comment);
}
}

View File

@@ -2,3 +2,30 @@
.bg-green {
background-color: #517B39;
}
@media (min-width: 992px){
.dropdown-menu .dropdown-toggle:after{
border-top: .3em solid transparent;
border-right: 0;
border-bottom: .3em solid transparent;
border-left: .3em solid;
}
.dropdown-menu .dropdown-menu{
margin-left:0; margin-right: 0;
}
.dropdown-menu li{
position: relative;
}
.nav-item .submenu{
display: none;
position: absolute;
left:100%; top:-7px;
}
.nav-item .submenu-left{
right:100%; left:auto;
}
.dropdown-menu > li:hover{ background-color: #f1f1f1 }
.dropdown-menu > li:hover > .submenu{
display: block;
}
}

18
build/js/site.js Normal file
View File

@@ -0,0 +1,18 @@
// Prevent closing from click inside dropdown
$(document).on('click', '.dropdown-menu', function (e) {
e.stopPropagation();
});
// make it as accordion for smaller screens
if ($(window).width() < 992) {
$('.dropdown-menu a').click(function(e){
e.preventDefault();
if($(this).next('.submenu').length){
$(this).next('.submenu').toggle();
}
$('.dropdown').on('hide.bs.dropdown', function () {
$(this).find('.submenu').hide();
})
});
}

View File

@@ -0,0 +1,520 @@
/*!
* Fancytree Taxonomy Browser
*
* Copyright (c) 2015, Martin Wendt (https://wwWendt.de)
*
* Released under the MIT license
* https://github.com/mar10/fancytree/wiki/LicenseInfo
*
* @version @VERSION
* @date @DATE
*/
/* global Handlebars */
/* eslint-disable no-console */
(function($, window, document) {
"use strict";
/*******************************************************************************
* Private functions and variables
*/
var taxonTree,
searchResultTree,
tmplDetails,
tmplInfoPane,
tmplMedia,
timerMap = {},
USER_AGENT = "Fancytree Taxonomy Browser/1.0",
GBIF_URL = "//api.gbif.org/v1/",
TAXONOMY_KEY = "d7dddbf4-2cf0-4f39-9b2a-bb099caae36c", // GBIF backbone taxonomy
SEARCH_PAGE_SIZE = 5,
CHILD_NODE_PAGE_SIZE = 200,
glyphOpts = {
preset: "bootstrap3",
map: {
expanderClosed: "glyphicon glyphicon-menu-right", // glyphicon-plus-sign
expanderLazy: "glyphicon glyphicon-menu-right", // glyphicon-plus-sign
expanderOpen: "glyphicon glyphicon-menu-down", // glyphicon-collapse-down
},
};
// Load and compile handlebar templates
$.get("details.tmpl.html", function(data) {
tmplDetails = Handlebars.compile(data);
Handlebars.registerPartial("tmplDetails", tmplDetails);
});
$.get("media.tmpl.html", function(data) {
tmplMedia = Handlebars.compile(data);
Handlebars.registerPartial("tmplMedia", tmplMedia);
});
$.get("info-pane.tmpl.html", function(data) {
tmplInfoPane = Handlebars.compile(data);
});
/** Update UI elements according to current status
*/
function updateControls() {
var query = $.trim($("input[name=query]").val());
$("#btnPin").attr("disabled", !taxonTree.getActiveNode());
$("#btnUnpin")
.attr("disabled", !taxonTree.isFilterActive())
.toggleClass("btn-success", taxonTree.isFilterActive());
$("#btnResetSearch").attr("disabled", query.length === 0);
$("#btnSearch").attr("disabled", query.length < 2);
}
/**
* Invoke callback after `ms` milliseconds.
* Any pending action of this type is cancelled before.
*/
function _delay(tag, ms, callback) {
/*jshint -W040:true */
var self = this;
tag = "" + (tag || "default");
if (timerMap[tag] != null) {
clearTimeout(timerMap[tag]);
delete timerMap[tag];
// console.log("Cancel timer '" + tag + "'");
}
if (ms == null || callback == null) {
return;
}
// console.log("Start timer '" + tag + "'");
timerMap[tag] = setTimeout(function() {
// console.log("Execute timer '" + tag + "'");
callback.call(self);
}, +ms);
}
/**
*/
function _callWebservice(cmd, data) {
return $.ajax({
url: GBIF_URL + cmd,
data: $.extend({}, data),
cache: true,
headers: { "Api-User-Agent": USER_AGENT },
dataType: "jsonp",
});
}
/**
*/
function updateItemDetails(key) {
$("#tmplDetails").addClass("busy");
$.bbq.pushState({ key: key });
$.when(
_callWebservice("species/" + key),
_callWebservice("species/" + key + "/speciesProfiles"),
_callWebservice("species/" + key + "/synonyms"),
_callWebservice("species/" + key + "/descriptions"),
_callWebservice("species/" + key + "/media")
).done(function(species, profiles, synonyms, descriptions, media) {
// Requests are resolved as: [ data, statusText, jqXHR ]
species = species[0];
profiles = profiles[0];
synonyms = synonyms[0];
descriptions = descriptions[0];
media = media[0];
var info = $.extend(species, {
profileList: profiles.results, // marine, extinct
profile:
profiles.results.length === 1 ? profiles.results[0] : null, // marine, extinct
synonyms: synonyms.results,
descriptions: descriptions.results,
descriptionsByLang: {},
media: media.results,
now: new Date().toString(),
});
$.each(info.descriptions, function(i, o) {
if (!info.descriptionsByLang[o.language]) {
info.descriptionsByLang[o.language] = [];
}
info.descriptionsByLang[o.language].push(o);
});
console.log("updateItemDetails", info);
$("#tmplDetails")
// .html(tmplDetails(info))
.removeClass("busy");
$("#tmplMedia")
// .html(tmplMedia(info))
.removeClass("busy");
$("#tmplInfoPane")
.html(tmplInfoPane(info))
.removeClass("busy");
$("[data-toggle='popover']").popover();
$(".carousel").carousel();
$("#mediaCounter").text("" + (media.results.length || ""));
// $("[data-toggle='collapse']").collapse();
updateControls();
});
}
/**
*/
function updateBreadcrumb(key, loadTreeNodes) {
var $ol = $("ol.breadcrumb").addClass("busy"),
activeNode = taxonTree.getActiveNode();
if (activeNode && activeNode.key !== key) {
activeNode.setActive(false); // deactivate, in case the new key is not found
}
$.when(
_callWebservice("species/" + key + "/parents"),
_callWebservice("species/" + key)
).done(function(parents, node) {
// Both requests resolved (result format: [ data, statusText, jqXHR ])
var nodeList = parents[0],
keyList = [];
nodeList.push(node[0]);
// Display as <OL> list (for Bootstrap breadcrumbs)
$ol.empty().removeClass("busy");
$.each(nodeList, function(i, o) {
var name = o.vernacularName || o.canonicalName;
keyList.push(o.key);
if ("" + o.key === "" + key) {
$ol.append(
$("<li class='active'>").append(
$("<span>", {
text: name,
title: o.rank,
})
)
);
} else {
$ol.append(
$("<li>").append(
$("<a>", {
href: "#key=" + o.key,
text: name,
title: o.rank,
})
)
);
}
});
if (loadTreeNodes) {
// console.log("updateBreadcrumb - loadKeyPath", keyList);
taxonTree.loadKeyPath("/" + keyList.join("/"), function(
n,
status
) {
// console.log("... updateBreadcrumb - loadKeyPath " + n.title + ": " + status);
switch (status) {
case "loaded":
n.makeVisible();
break;
case "ok":
n.setActive();
// n.makeVisible();
break;
}
});
}
});
}
/**
*/
function search(query) {
query = $.trim(query);
console.log("searching for '" + query + "'...");
// Store the source options for optional paging
searchResultTree.lastSourceOpts = {
// url: GBIF_URL + "species/match", // Fuzzy matches scientific names against the GBIF Backbone Taxonomy
url: GBIF_URL + "species/search", // Full text search of name usages covering the scientific and vernacular name, the species description, distribution and the entire classification across all name usages of all or some checklists
data: {
q: query,
datasetKey: TAXONOMY_KEY,
// name: query,
// strict: "true",
// hl: true,
limit: SEARCH_PAGE_SIZE,
offset: 0,
},
cache: true,
// headers: { "Api-User-Agent": USER_AGENT }
// dataType: "jsonp"
};
$("#searchResultTree").addClass("busy");
searchResultTree
.reload(searchResultTree.lastSourceOpts)
.done(function(result) {
// console.log("search returned", result);
if (result.length < 1) {
searchResultTree.getRootNode().setStatus("nodata");
}
$("#searchResultTree").removeClass("busy");
// https://github.com/tbasse/jquery-truncate
// SLOW!
// $("div.truncate").truncate({
// multiline: true
// });
updateControls();
});
}
/*******************************************************************************
* Pageload Handler
*/
$(function() {
$("#taxonTree").fancytree({
extensions: ["filter", "glyph", "wide"],
filter: {
mode: "hide",
},
glyph: glyphOpts,
autoCollapse: true,
activeVisible: true,
autoScroll: true,
source: {
url: GBIF_URL + "species/root/" + TAXONOMY_KEY,
data: {},
cache: true,
// dataType: "jsonp"
},
init: function(event, data) {
updateControls();
$(window).trigger("hashchange"); // trigger on initial page load
},
lazyLoad: function(event, data) {
data.result = {
url: GBIF_URL + "species/" + data.node.key + "/children",
data: {
limit: CHILD_NODE_PAGE_SIZE,
},
cache: true,
// dataType: "jsonp"
};
// store this request options for later paging
data.node.lastSourceOpts = data.result;
},
postProcess: function(event, data) {
var response = data.response;
data.node.info("taxonTree postProcess", response);
data.result = $.map(response.results, function(o) {
return (
o && {
title: o.vernacularName || o.canonicalName,
key: o.key,
nubKey: o.nubKey,
folder: true,
lazy: true,
}
);
});
if (response.endOfRecords === false) {
// Allow paging
data.result.push({
title: "(more)",
statusNodeType: "paging",
});
} else {
// No need to store the extra data
delete data.node.lastSourceOpts;
}
},
activate: function(event, data) {
$("#tmplDetails").addClass("busy");
$("ol.breadcrumb").addClass("busy");
updateControls();
_delay("showDetails", 500, function() {
updateItemDetails(data.node.key);
updateBreadcrumb(data.node.key);
});
},
clickPaging: function(event, data) {
// Load the next page of results
var source = $.extend(
true,
{},
data.node.parent.lastSourceOpts
);
source.data.offset = data.node.parent.countChildren() - 1;
data.node.replaceWith(source);
},
});
$("#searchResultTree").fancytree({
extensions: ["table", "wide"],
source: [{ title: "No Results." }],
minExpandLevel: 2,
icon: false,
table: {
nodeColumnIdx: 2,
},
postProcess: function(event, data) {
var response = data.response;
data.node.info("search postProcess", response);
data.result = $.map(response.results, function(o) {
var res = $.extend(
{
title: o.scientificName,
key: o.key,
},
o
);
return res;
});
// Append paging link
if (
response.count != null &&
response.offset + response.limit < response.count
) {
data.result.push({
title:
"(" +
(response.count -
response.offset -
response.limit) +
" more)",
statusNodeType: "paging",
});
}
data.node.info("search postProcess 2", data.result);
},
// loadChildren: function(event, data) {
// $("#searchResultTree td div.cell").truncate({
// multiline: true
// });
// },
renderColumns: function(event, data) {
var i,
node = data.node,
$tdList = $(node.tr).find(">td"),
cnList = node.data.vernacularNames
? $.map(node.data.vernacularNames, function(o) {
return o.vernacularName;
})
: [];
i = 0;
function _setCell($cell, text) {
$("<div class='truncate'>")
.attr("title", text)
.text(text)
.appendTo($cell);
}
$tdList.eq(i++).text(node.key);
$tdList.eq(i++).text(node.data.rank);
i++; // #1: node.title = scientificName
// $tdList.eq(i++).text(cnList.join(", "));
_setCell($tdList.eq(i++), cnList.join(", "));
$tdList.eq(i++).text(node.data.canonicalName);
// $tdList.eq(i++).text(node.data.accordingTo);
_setCell($tdList.eq(i++), node.data.accordingTo);
$tdList.eq(i++).text(node.data.taxonomicStatus);
$tdList.eq(i++).text(node.data.nameType);
$tdList.eq(i++).text(node.data.numOccurrences);
$tdList.eq(i++).text(node.data.numDescendants);
// $tdList.eq(i++).text(node.data.authorship);
_setCell($tdList.eq(i++), node.data.authorship);
// $tdList.eq(i++).text(node.data.publishedIn);
_setCell($tdList.eq(i++), node.data.publishedIn);
},
activate: function(event, data) {
if (data.node.isStatusNode()) {
return;
}
_delay("activateNode", 500, function() {
updateItemDetails(data.node.key);
updateBreadcrumb(data.node.key);
});
},
clickPaging: function(event, data) {
// Load the next page of results
var source = $.extend(
true,
{},
searchResultTree.lastSourceOpts
);
source.data.offset = data.node.parent.countChildren() - 1;
data.node.replaceWith(source);
},
});
taxonTree = $.ui.fancytree.getTree("#taxonTree");
searchResultTree = $.ui.fancytree.getTree("#searchResultTree");
// Bind a callback that executes when document.location.hash changes.
// (This code uses bbq: https://github.com/cowboy/jquery-bbq)
$(window).on("hashchange", function(e) {
var key = $.bbq.getState("key");
console.log("bbq key", key);
if (key) {
updateBreadcrumb(key, true);
}
}); // don't trigger now, since we need the the taxonTree root nodes to be loaded first
$("input[name=query]")
.on("keyup", function(e) {
var query = $.trim($(this).val()),
lastQuery = $(this).data("lastQuery");
if ((e && e.which === $.ui.keyCode.ESCAPE) || query === "") {
$("#btnResetSearch").click();
return;
}
if (e && e.which === $.ui.keyCode.ENTER && query.length >= 2) {
$("#btnSearch").click();
return;
}
if (query === lastQuery || query.length < 2) {
console.log("Ignored query '" + query + "'");
return;
}
$(this).data("lastQuery", query);
_delay("search", 1, function() {
$("#btnSearch").click();
});
$("#btnResetSearch").attr("disabled", query.length === 0);
$("#btnSearch").attr("disabled", query.length < 2);
})
.focus();
$("#btnResetSearch").click(function(e) {
$("#searchResultPane").collapse("hide");
$("input[name=query]").val("");
searchResultTree.clear();
updateControls();
});
$("#btnSearch")
.click(function(event) {
$("#searchResultPane").collapse("show");
search($("input[name=query]").val());
})
.attr("disabled", true);
$("#btnPin").click(function(event) {
taxonTree.filterBranches(function(n) {
return n.isActive();
});
updateControls();
});
$("#btnUnpin").click(function(event) {
taxonTree.clearFilter();
updateControls();
});
// -----------------------------------------------------------------------------
}); // end of pageload handler
})(jQuery, window, document);

View File

@@ -14,7 +14,6 @@
"arrilot/laravel-widgets": "^3.13",
"barryvdh/laravel-dompdf": "^0.9",
"barryvdh/laravel-snappy": "^0.4.7",
"beyondcode/laravel-comments": "^1.2",
"box/spout": "^3.3",
"browner12/helpers": "^3.0",
"cesargb/laravel-cascade-delete": "^1.2",
@@ -25,7 +24,6 @@
"darryldecode/cart": "^4.1",
"datatables/datatables": "^1.10",
"ddzobov/laravel-pivot-softdeletes": "^2.1",
"deployer/deployer": "^6.8",
"dompdf/dompdf": "^1.0.2",
"dyrynda/laravel-cascade-soft-deletes": "^4.1",
"eduardokum/laravel-mail-auto-embed": "^1.0",
@@ -54,9 +52,9 @@
"league/climate": "^3.5",
"league/period": "^4.9",
"livewire/livewire": "^2.4",
"lorisleiva/laravel-deployer": "^0.3.2",
"maatwebsite/excel": "^3.1",
"mad-web/laravel-initializer": "^3.3",
"maximeb/laravel-8-paybox-gateway": "^1.1",
"moneyphp/money": "^3.3",
"mpdf/mpdf": "^8.0",
"mpociot/teamwork": "^6.1",
@@ -72,7 +70,6 @@
"santigarcor/laratrust": "^6.0",
"sebastienheyd/boilerplate": "^7.5",
"sensiolabs/security-checker": "^6.0",
"sheub/ban-france-provider": "^1.0@dev",
"smajohusic/laravel-mail-logger": "^1.0",
"spatie/eloquent-sortable": "^3.11",
"spatie/image-optimizer": "^1.4",
@@ -95,16 +92,12 @@
"barryvdh/laravel-debugbar": "^3.5",
"bestmomo/laravel5-artisan-language": "^0.3",
"beyondcode/laravel-dump-server": "^1.0",
"beyondcode/laravel-er-diagram-generator": "^1.2",
"cybercog/laravel-whoops-editor": "^3.0",
"daniel-werner/php-quality-tools": "^1.1",
"enlightn/enlightn": "^1.16",
"facade/ignition": "^2.9",
"fakerphp/faker": "^1.13",
"geekality/timer": "^1.2",
"imanghafoori/laravel-microscope": "^1.0",
"mockery/mockery": "^1.4.2",
"mtolhuys/laravel-schematics": "^0.10.3",
"nunomaduro/collision": "^5.4",
"nunomaduro/larastan": "^0.7",
"nunomaduro/laravel-mojito": "^0.2.6",
@@ -113,6 +106,7 @@
"phpmetrics/phpmetrics": "^2.7",
"phpunit/phpunit": "^9.3.3",
"spatie/laravel-web-tinker": "^1.4",
"squizlabs/php_codesniffer": "3.*",
"staudenmeir/dusk-updater": "^1.2",
"wnx/laravel-stats": "^2.4",
"wulfheart/pretty_routes": "^0.3.0"

View File

@@ -1,5 +1,5 @@
<div class="row">
<div class="col-md-8">
<div class="col-lg-8">
<div class="row mb-3">
<div class="col-3">
@@ -55,7 +55,7 @@
</div>
</div>
<div class="col-md-4">
<div class="col-lg-4">
<div id="product_images_inherited">
@include('Admin.Shop.Articles.partials.product.images')
</div>

View File

@@ -7,7 +7,7 @@
@if ($inherited['tags'])
<h6> Tags</h6>
@foreach ($inherited['tags'] as $tag)
<span class="btn btn-xs">{{ $tag['name'] }}</span>
<button type="button" class="btn btn-secondary btn-xs">{{ $tag['group']['name'] }}-{{ $tag['name'] }}</button>
@endforeach
@endif
@endcomponent

View File

@@ -1,5 +1,5 @@
<div class="row mb-3">
<div class="col-3">
<div class="col-6">
<div class="row mb-3">
<div class="col-12">
{{ Form::label('article_id', 'Article') }}
@@ -20,15 +20,7 @@
@include('components.select', ['name' => 'tariff_id', 'id_name' => 'tariff_id', 'list' => $tariffs ?? null, 'value' => $offer['tariff_id'] ?? null, 'with_empty' => '', 'class' => 'select2 select_tariffs'])
</div>
</div>
</div>
<div class="col-6">
@component('components.card', ['title' => 'Previsualisation'])
<div id="preview-article"></div>
<div id="preview-variation"></div>
<div id="preview-tariff"></div>
@endcomponent
</div>
<div class="col-3">
@component('components.card', ['title' => 'Disponibilité'])
<div class="row mb-3">
<div class="col-12 col-xl-6">
@@ -58,6 +50,14 @@
</div>
@endcomponent
</div>
<div class="col-6">
@component('components.card', ['title' => 'Previsualisation'])
<div id="preview-article"></div>
<div id="preview-variation"></div>
<div id="preview-tariff"></div>
@endcomponent
</div>
</div>
@include('components.save')

View File

@@ -53,56 +53,57 @@
</form>
<script>
function handleAddPrice() {
$('#add_price').click( function () {
var index = $('#prices-table tbody tr').length;
$.get("{{ route('Admin.Shop.PriceListValues.addPrice') }}/" + index, function(data) {
$("#prices-table").append(data);
})
handlePrices();
<script>
function handleAddPrice() {
$('#add_price').click( function () {
var index = $('#prices-table tbody tr').length;
$.get("{{ route('Admin.Shop.PriceListValues.addPrice') }}/" + index, function(data) {
$("#prices-table").append(data);
})
}
function handle_prices() {
$('.price').change(function() {
$col_tax = $(this).parent().parent().find('.tax')();
tax_selected = $col_tax.find('select option:selected').text();
price_taxed = $(this).val() * (1 + (tax_selected / 100));
price_taxed = price_taxed.toFixed(2);
$(this).parent().parent().find('.price_taxed').val(price_taxed);
})
}
function handle_taxes() {
$('.tax').change(function() {
tax_selected = $(this).text();
price = $(this).parent().parent().find('.price').val();
price_taxed = price * (1 + (tax_selected / 100));
price_taxed = price_taxed.toFixed(2);
$(this).parent().parent().find('.price_taxed').val(price_taxed);
})
}
function handle_prices_taxed() {
$('.price_taxed').change(function() {
$col_tax = $(this).parent().parent().find('.tax')();
tax_selected = $col_tax.find('select option:selected').text();
price = $(this).val() / (1 + (tax_selected / 100));
price = price.toFixed(2);
$(this).parent().parent().find('.price').val(price);
})
}
function handlePrices() {
handle_prices();
handle_taxes();
handle_prices_taxed();
}
$(function() {
handleAddPrice();
handlePrices();
});
})
}
</script>
function handle_prices() {
$('.price').change(function() {
$col_tax = $(this).parent().parent().find('.tax');
tax_selected = $col_tax.find('option:selected').text();
price_taxed = $(this).val() * (1 + (tax_selected / 100));
price_taxed = price_taxed.toFixed(2);
console.log(price_taxed);
$(this).parent().parent().find('.price_taxed').val(price_taxed);
})
}
function handle_taxes() {
$('.tax').change(function() {
tax_selected = $(this).find('option:selected').text();
price = $(this).parent().parent().find('.price').val();
price_taxed = price * (1 + (tax_selected / 100));
price_taxed = price_taxed.toFixed(2);
$(this).parent().parent().find('.price_taxed').val(price_taxed);
})
}
function handle_prices_taxed() {
$('.price_taxed').change(function() {
$col_tax = $(this).parent().parent().find('.tax');
tax_selected = $col_tax.find('option:selected').text();
price = $(this).val() / (1 + (tax_selected / 100));
price = price.toFixed(2);
$(this).parent().parent().find('.price').val(price);
})
}
function handlePrices() {
handle_prices();
handle_taxes();
handle_prices_taxed();
}
$(function() {
handleAddPrice();
handlePrices();
});
</script>

View File

@@ -50,7 +50,7 @@
</div>
</div>
<div class="row">
<div class="row mb-3">
<div class="col-12">
@if ($tariff['id'] ?? false)
@@ -70,6 +70,7 @@
@include('components.save')
@include('load.form.editor')
@include('load.form.save')
@include('load.form.select2')
@include('load.layout.modal')
@@ -77,19 +78,21 @@
<script>
$(function() {
initEditor();
initSelect2();
initSaveForm('#tariffs-form');
});
function PriceListCreate() {
var tariff_id = $('#id').val();
var url_open = "{{ route('Admin.Shop.PriceLists.modalCreate') }}/" + tariff_id;
var url_save = "{{ route('Admin.Shop.PriceLists.storeAjax') }}";
openModal("{{ __('price_list') }}", '#price_list-form', url_open, url_save, "PriceListRefresh();");
openModal("{{ __('price_list') }}", '#price_list-form', url_open, url_save, "PriceListRefresh();","extra-large");
}
function PriceListEdit(id) {
var url_open = "{{ route('Admin.Shop.PriceLists.modalEdit') }}/" + id;
var url_save = "{{ route('Admin.Shop.PriceLists.storeAjax') }}";
openModal("{{ __('price_list') }}", '#price_list-form', url_open, url_save, "PriceListRefresh();");
openModal("{{ __('price_list') }}", '#price_list-form', url_open, url_save, "PriceListRefresh();","extra-large");
}
function PriceListRefresh()

View File

@@ -3,8 +3,5 @@
])
@section('content')
@include("Shop.layout.partials.block-breadcrumb")
@include("Shop.layout.partials.category")
@include('Shop.layout.partials.category_articles')
@endsection

View File

@@ -1,57 +0,0 @@
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>OpenSemis</title>
<meta name="description" content="Boutique propulsée par HumaN.E.T">
<meta name="keywords" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/vnd.microsoft.icon" href="img/favicon.ico?1528709483">
<link rel="shortcut icon" type="image/x-icon" href="img/favicon.ico?1528709483">
<link rel="stylesheet" href="/css/theme.css" type="text/css" media="all">
{{ include("Shop._partials.presta_js")}}
</head>
<body id="index" class="lang-fr country-us currency-usd layout-full-width page-index tax-display-disabled">
<main>
{{ include("Shop._partials.header") }}
{{ include("Shop._partials.notifications") }}
<div id="top_home">
<div id="spin-wrapper"></div>
<div id="siteloader">
<div class="loader"></div>
</div>
{{ include("Shop._partials.slider") }}
{{ include("Shop._partials.block-banner") }}
{{ include("Shop._partials.block-products") }}
{{ include("Shop._partials.block-breadcrumb") }}
{{ include("Shop._partials.wrapper") }}
{{ include("Shop._partials.block-bottom")}}
{{ include("Shop._partials.footer")}}
</div>
</main>
<a id="slidetop" href="#" >&nbsp;</a>
<script type="text/javascript" src="/js/theme.js" ></script>
</body>
</html>

View File

@@ -9,13 +9,13 @@
<meta name="robots" content="noindex, nofollow">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>OpenSemis</title>
<title>Jardin'enVie</title>
<meta name="description" content="Vente de semences, variété anciennes">
<meta name="keywords" content="">
<link rel="icon" type="image/vnd.microsoft.icon" href="img/favicon.ico">
<link rel="shortcut icon" type="image/x-icon" href="img/favicon.ico">
<link rel="stylesheet" href="css/site.min.css" type="text/css" media="all">
<link rel="stylesheet" href="/css/site.min.css" type="text/css" media="all">
@stack('css')
@@ -42,7 +42,7 @@
</div>
<script type="text/javascript" src="js/site.min.js" ></script>
<script type="text/javascript" src="/js/site.min.js" ></script>
@stack('scripts')

View File

@@ -1,7 +1,7 @@
<div class="card" style="width: 18rem;">
<img src="{{ App\Repositories\Shop\Articles::getThumbSrc($article['image']) }}" class="card-img-top" alt="...">
<div class="card">
<img src="{{ App\Repositories\Shop\Articles::getPreviewSrc($offer['article']['image']) }}" class="card-img-top" alt="...">
<div class="card-body">
<span class="card-title">{{ $article['name'] }}</span>
<span class="card-title">{{ $offer['article']['name'] }}</span>
<span class="pull-right">
<i class="fa fa-heart"></i>
</span>

View File

@@ -1,6 +1,6 @@
<div class="row">
@foreach ($articles as $article)
<div class="col-3">
@foreach ($offers as $offer)
<div class="col-sm-6 col-md-3 col-lg-2">
@include('Shop.layout.partials.article')
</div>
@endforeach

View File

@@ -7,15 +7,13 @@
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ $category['name'] }}
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
@foreach ($category['children'] as $children)
<a class="dropdown-item" href="{{ $children['id'] }}">{{ $children['name'] }}</a>
@endforeach
</div>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
@include('Shop.layout.partials.submenu', ['categories' => $category['children']])
</ul>
</li>
@else
<li class="nav-item">
<a class="nav-link" href="{{ $category['id'] }}">{{ $category['name'] }}</a>
<a class="nav-link" href="{{ route('Shop.Categories.show', ['id' => $category['id']]) }}">{{ $category['name'] }}</a>
</li>
@endif
@endforeach

View File

@@ -0,0 +1,19 @@
@foreach ($categories as $category)
<li>
@if ($category['children'] ?? false)
<a class="dropdown-item" href="#">
<div class="w-100">
{{ $category['name'] }}
<span style="float: right;">
<i class="fa fa-caret-right"></i>
</span>
</div>
</a>
<ul class="submenu dropdown-menu">
@include('Shop.layout.partials.submenu', ['categories' => $category['children']])
</ul>
@else
<a class="dropdown-item" href="{{ route('Shop.Categories.show', ['id' => $category['id']]) }}">{{ $category['name'] }}</a>
@endif
</li>
@endforeach

View File

@@ -0,0 +1,21 @@
@extends('Shop.layout.layout', [
'title' => __('home.title'),
])
@section('content')
<div class="row">
<div class="col-8">
<h1 style="font-size: 2em;">{{ $category['name'] }}</h1>
<h3 style="font-size: 1.2em;">{!! $category['description'] !!}</h3>
</div>
<div class="col-4">
@include('Shop.layout.partials.category_add')
</div>
</div>
<div class="row">
<div class="col-12">
@include('Shop.layout.partials.category_articles')
</div>
</div>
@endsection

View File

@@ -1,9 +1,9 @@
<?php
Route::prefix('Shop')->namespace('Shop')->name('Shop.')->group(function () {
include( __DIR__ . '/Articles.php');
include( __DIR__ . '/Categories.php');
include( __DIR__ . '/Customers.php');
include( __DIR__ . '/Invoices.php');
include( __DIR__ . '/Orders.php');
include( __DIR__ . '/Articles.php');
include( __DIR__ . '/Categories.php');
});