À propos de nous
Vous êtes fan de football ? Cela tombe bien car nous aussi ! La Maison du Maillot est une société spécialisée dans la vente de vêtements de sport depuis 2021, élaborée par une équipe de passionnés. Nous sommes basés principalement en France. Nos produits sont manufacturés en Chine où une de nos équipes est également sur place afin de vous offrir des produits de qualités aux meilleurs prix.
NOS MAILLOTS ?
Nos maillots sont d’une qualité similaire aux maillots vendus 3 fois plus cher ailleurs. Tous nos maillots sont expédiés depuis la Chine.
SOMMES NOUS FIABLES ?
La Maison du Maillot a vu le jour en 2021 sous le nom de Le Maillot de Foot et depuis nous vendons toujours des maillots aux quatre coins du monde avec la priorité de satisfaire et de fidéliser notre clientèle. Nous travaillons chaque jour dans le but de vous offrir la meilleure expérience possible sur notre site internet et un moment inoubliable. Avec Le Maillot 2 Foot vous avez à faire à de véritables passionnés !
UNE BOUTIQUE ?
Nous n'avons pas de boutique ou de magasin, nous vendons exclusivement sur internet ce qui nous permet de vous proposer des prix très bas toute l'année !
NOUS CONTACTER
Nous disposons d'un formulaire de contact ou notre Service après-vente se fera un plaisir de vous répondre par mail : service@lemaillotfoot.com
LE MOT DE LA FIN ?
Notre priorité ? Votre satisfaction !
(function() {
const STATUS = {
LOADING: 'loading',
FINISH: 'finish'
};
const RESULT = {
EMPTY: 'data-empty'
};
class SPZCustomCartSku extends SPZ.BaseElement {
renderData = [];
/**
* add to cart reselect item, and delete process:
* 1. record reselect id before show reselect modal
* 2. add to cart success, mark `needDeleteReselectRecord` to true
* 3. close reselect modal / drawer
* 4. spz-cart re-render, triggered mounted event
* 5. call refresh
*/
// mark delete reselect id
recordReselectId = null;
// mark should delete reselect record after spz-cart mounted event
needDeleteReselectRecord = false;
refreshLock = false;
addToCartSuccess = false;
// cache paused refresh data
refreshDataCache = [];
// cache similar products data, for manual add to cart
similarData = [];
constructor(element) {
super(element);
this.xhr_ = SPZServices.xhrFor(this.win);
this.action_ = SPZServices.actionServiceForDoc(this.element);
}
setupAction_() {
this.registerAction('refresh', (invocation) => {
const data = invocation && invocation.args && invocation.args.data || {};
this.refresh(data);
});
this.registerAction('deleteReselect', SPZCore.Types.debounce(
this.win,
(invocation) => {
this.deleteReselect(invocation?.args?.id);
},
200
));
this.registerAction('deleteInvalid', SPZCore.Types.debounce(
this.win,
(invocation) => {
this.deleteInvalid(invocation?.args?.id);
},
200
));
this.registerAction('setReselectRecordId', (invocation) => {
this.setReselectRecordId(invocation?.args?.id);
});
this.registerAction('clearNeedReselectRecord', (invocation) => {
this.clearNeedReselectRecord();
});
this.registerAction('registerDeleteReselectTask', (invocation) => {
this.registerDeleteReselectTask(invocation?.args?.data);
});
this.registerAction('lockRefresh', (invocation) => {
this.lockRefresh();
});
this.registerAction('releaseRefreshLock', (invocation) => {
this.releaseRefreshLock();
});
this.registerAction('manualAddToCart', (invocation) => {
this.manualAddToCart(invocation?.args?.id);
});
this.registerAction('syncSimilarData', (invocation) => {
this.syncSimilarData(invocation?.args?.data);
});
// DEBUG
this.registerAction('log', (invocation) => {
const data = invocation && invocation.args && invocation.args.data || {};
console.log('log', invocation);
});
}
buildCallback() {
this.setupAction_();
}
isLayoutSupported(layout) {
return true;
}
/**
* 数据去重
* @param {Array} data
*/
uniq_(data) {
const result = [];
for(let i = 0; i < data.length; i++) {
if(!result.includes(data[i])) {
result.push(data[i]);
}
}
return result;
}
checkRefreshLock() {
if (this.refreshLock) {
return false;
}
return true;
}
setLoading(isLoading) {
SPZCore.Dom.toggleAttribute(this.element, STATUS.LOADING, isLoading);
SPZCore.Dom.toggleAttribute(this.element, STATUS.FINISH, !isLoading);
}
setDataResult(data) {
const isDataEmpty = !data.reselectSkus.length && !data.invalidSkus.length && !data.line_items.length;
SPZCore.Dom.toggleAttribute(this.element, RESULT.EMPTY, isDataEmpty);
}
// 存在多次请求顺序问题
async refresh(_data) {
// 接口失败时返回数据不为对象
if (!(typeof _data === 'object' && _data.line_items && _data.line_items.length > 0)) {
const newData = {
line_items: [],
reselectSkus: [],
invalidSkus: [],
displayInvalidSkus: []
};
this.trigger_('refreshError', newData);
this.setLoading(false);
return;
}
if (!this.checkRefreshLock()) {
this.setRefreshCache(_data);
return;
}
this.setLoading(true);
let data = _data;
if (this.needDeleteReselectRecord && this.recordReselectId) {
let hasError = false;
try {
data = await this.deleteReselectRecordBeforeRefresh(_data);
} catch (e) {
hasError = true;
console.error(e);
const newData = {
...data,
reselectSkus: [],
invalidSkus: [],
displayInvalidSkus: []
};
this.trigger_('refreshError', newData);
this.setLoading(false);
this.setDataResult(newData);
return;
}
this.needDeleteReselectRecord = false;
if (hasError) {
return;
}
}
// 获取失效商品
const invisibleItems = data.ineffectives;
// 获取失效商品内仅售罄商品的sku
const soldOutItems = invisibleItems.filter(item => item.reason === "line_item_sold_out");
// 通过失效 sku 获取 spu, 注意去重
const soldOutSpuIds = this.uniq_(soldOutItems.map(item => item.product_id));
const querySpuIds = soldOutSpuIds.map(spuId => `ids[]=${spuId}`).join('&');
if (!soldOutSpuIds.length) {
const newData = {
...data,
reselectSkus: [],
invalidSkus: [],
displayInvalidSkus: []
};
this.trigger_('refreshSuccess', newData);
this.renderData = newData;
this.setLoading(false);
this.setDataResult(newData);
return;
}
// 请求 spu 下其他 sku 库存
this.xhr_.fetchJson(`/api/product/list?limit=${soldOutSpuIds.length}&${querySpuIds}`)
.then(res => {
const reselectSkus = [];
const invalidSkus = [];
// spu 维度展示
const displayInvalidSkus = [];
res.data.list.forEach(product => {
// spu 匹配, 存在多 sku 情况
const soldOutSkus = soldOutItems.filter(item => item.product_id === product.id);
if (!soldOutSkus.length) {
return;
}
// 通过失效 sku 获取 spu 下其他 sku 库存, 存在其他可用库存时标记为 "Reselect" 按钮可用
//const allowReselect = product.variants
// .filter(variant => variant.option1 === soldOutProduct.variant.option1 && variant.option2 === soldOutProduct.variant.option2 && variant.option3 === soldOutProduct.variant.option3)
// .some(variant => variant.available);
// 查询售罄 sku 对应商品是否可加购, 标记为 Reselect 可用项
if (product.available) {
reselectSkus.push(...soldOutSkus);
// 若商品不可用(全部 sku 售罄), 归纳到失效商品列表
} else {
invalidSkus.push(...soldOutSkus);
// spu 维度, 仅添加一项 sku
displayInvalidSkus.push(soldOutSkus[0]);
}
});
const newData = {
...data,
reselectSkus,
invalidSkus,
displayInvalidSkus
};
this.trigger_('refreshSuccess', newData);
this.renderData = newData;
this.setLoading(false);
this.setDataResult(newData);
})
.catch(err => {
this.setLoading(false);
console.error(err);
this.trigger_('refreshError', data);
}).finally(() => {
});
}
async deleteReselect(id, ignoreEmit) {
if (!id) {
return;
}
const targetSku = this.renderData.reselectSkus.find(item => item.id === id);
try {
const res = await this.xhr_.fetchJson(`/api/cart/${targetSku.variant_id}`, {
method: 'DELETE',
body: {
id: targetSku.id,
product_id: targetSku.product_id,
variant_id: targetSku.variant_id,
}
});
const newData = {
...this.renderData,
reselectSkus: this.renderData.reselectSkus.filter(item => item.id !== id),
};
this.renderData = newData;
!ignoreEmit && this.trigger_('deleteSuccess', newData);
} catch (err) {
console.error(err);
!ignoreEmit && this.trigger_('deleteError', err);
}
}
deleteInvalid(id) {
if (!id) {
return;
}
const targetSku = this.renderData.invalidSkus.find(item => item.id === id);
this.xhr_.fetchJson(`/api/cart/${targetSku.variant_id}`, {
method: 'DELETE',
body: {
id: targetSku.id,
product_id: targetSku.product_id,
variant_id: targetSku.variant_id,
}
})
.then(res => {
const newData = {
...this.renderData,
invalidSkus: this.renderData.invalidSkus.filter(item => item.id !== id),
displayInvalidSkus: this.renderData.displayInvalidSkus.filter(item => item.id !== id),
};
this.trigger_('deleteSuccess', newData);
this.renderData = newData;
})
.catch(err => {
console.error(err);
this.trigger_('deleteError', err);
});
}
// record reselect sku id before show reselect modal
setReselectRecordId(id) {
if (!id) {
return;
}
this.recordReselectId = id;
}
async deleteReselectRecordBeforeRefresh(data) {
if (!this.recordReselectId) {
return;
}
await this.deleteReselect(this.recordReselectId, true);
return {
...data,
ineffectives: data.ineffectives.filter(item => item.id !== this.recordReselectId)
}
}
clearNeedReselectRecord() {
this.needDeleteReselectRecord = false;
}
registerDeleteReselectTask(productData) {
const targetSku = this.renderData.reselectSkus.find(item => item.id === this.recordReselectId);
if (targetSku?.variant_id && productData?.variant.id) {
if (targetSku.variant_id === productData?.variant.id) {
this.needDeleteReselectRecord = false;
return;
}
}
this.needDeleteReselectRecord = true;
}
// pause cart refresh(trigger by similar products)
lockRefresh() {
if (this.refreshLock) {
return;
}
this.refreshLock = true;
}
releaseRefreshLock() {
if (!this.refreshLock) {
return;
}
this.refreshLock = false;
this.refreshWithCache();
}
// direct add_to_cart(trigger by similar products)
async manualAddToCart(id) {
const target = this.similarData.find(item => item.id === id);
this.lockRefresh();
try {
const res = await this.xhr_.fetchJson(`/api/cart`, {
method: 'POST',
body: {
note: '',
product_id: target.id,
quantity: '1',
variant_id: target.variants[0].id,
refer_info: {
source: 'add_to_cart'
}
}
});
const newCartItems = res.data.items;
this.setRefreshCache(newCartItems, true);
} catch (err) {
console.error(err);
}
}
syncSimilarData(data) {
this.similarData = data.data;
}
setRefreshCache(data, patch) {
if (patch) {
this.refreshDataCache = {
...this.refreshDataCache,
line_items: [...this.refreshDataCache.line_items, ...data]
};
} else {
this.refreshDataCache = data;
}
}
refreshWithCache() {
this.refresh(this.refreshDataCache);
}
mountCallback() {
}
unmountCallback() {
}
/**
* trigger event
* @param {Object} data
*/
trigger_(name, data) {
const event = SPZUtils.Event.create(this.win, `spz-custom-cart-sku.${name}`, {
data,
});
this.action_.trigger(this.element, name, event);
}
}
SPZ.defineElement('spz-custom-cart-sku', SPZCustomCartSku);
}())
(function () {
class SPZCustomCartTrack extends SPZ.BaseElement {
constructor(element) {
super(element);
this.action_ = SPZServices.actionServiceForDoc(this.element);
}
isLayoutSupported(layout) {
return true;
}
buildCallback() {
this.setupAction_();
}
hash(val) {
const hashKey = Object.keys(val).sort((a, b) => a - b).reduce((acc, k) => {
acc += `{'${k}':'${val[k]}'}`;
return acc;
}, '');
return hashKey;
}
trackExtra(key, value) {
console.log('trackExtra...', key, value);
if (!window.sa) {
return;
}
const hashKey = this.hash(value);
let hasExtraInfo = false;
if (window.sa.eventInfo && window.sa.eventInfo[key] && window.sa.eventInfo[key].extra_properties) {
hasExtraInfo = window.sa.eventInfo[key].extra_properties.some(p => {
return hashKey === this.hash(p);
});
}
if (hasExtraInfo) {
return;
}
window.sa && window.sa.registerExtraInfo(key, value);
}
delExtraTrack(key, value) {
const hashKey = this.hash(value);
if (window.sa.eventInfo && window.sa.eventInfo[key] && window.sa.eventInfo[key].extra_properties) {
window.sa.eventInfo[key].extra_properties = window.sa.eventInfo[key].extra_properties.filter(p => hashKey !== this.hash(p));
}
}
track(key, value) {
console.log('tracking...', key, value);
window.sa && window.sa.track(key, value);
}
setupAction_() {
this.registerAction('registerReselectAtc', () => {
this.trackExtra('add_to_cart', {
function_name: 'Farida',
action_type: 'reselect'
});
});
this.registerAction('clearReselectAtc', () => {
this.delExtraTrack('add_to_cart', {
function_name: 'Farida',
action_type: 'reselect'
});
});
this.registerAction('registerSimilarAtc', () => {
this.trackExtra('add_to_cart', {
function_name: 'Farida',
action_type: 'similar_product'
});
});
this.registerAction('clearSimilarAtc', () => {
this.delExtraTrack('add_to_cart', {
function_name: 'Farida',
action_type: 'similar_product'
});
});
const clickParams = {
business_type: 'product_plugin',
event_name: 'function_click',
function_name: 'Farida',
plugin_name: 'Farida',
template_name: 'cart',
template_type: '13',
module: 'online_store',
module_type: 'online_store',
tab_name: '',
card_name: '',
event_developer: 'ccbken',
event_type: 'click',
};
this.registerAction('trackDelReselect', () => {
this.track('function_click', {
...clickParams,
event_info: JSON.stringify({
action_type: 'cart_delete',
element_type: 'sku'
})
});
});
this.registerAction('trackClickReselect', () => {
this.track('function_click', {
...clickParams,
event_info: JSON.stringify({
action_type: 'reselect',
element_type: 'sku'
})
});
});
this.registerAction('trackDelSimilar', () => {
this.track('function_click', {
...clickParams,
event_info: JSON.stringify({
action_type: 'cart_delete',
element_type: 'spu'
})
});
});
this.registerAction('trackClickSimilar', () => {
this.track('function_click', {
...clickParams,
event_info: JSON.stringify({
action_type: 'reselect',
element_type: 'spu'
})
});
});
this.registerAction('trackOpenSimilar', () => {
this.track('function_expose', {
...clickParams,
event_name: 'function_expose',
event_type: 'expose',
event_info: JSON.stringify({
popup_name: 'farida_product_popup'
})
});
});
}
}
SPZ.defineElement('spz-custom-cart-track', SPZCustomCartTrack);
}())