This commit is contained in:
Vladislav 2026-07-20 14:24:33 -04:00
parent cb357add59
commit 837cba1aab
5 changed files with 371 additions and 118 deletions

View File

@ -4033,7 +4033,7 @@
" user: Dict = Security(get_current_user)\n",
"):\n",
" data = await invitations_collection.find_one({'_id': ObjectId(invitation_id)})\n",
" \n",
"\n",
" return templates.TemplateResponse(\n",
" request=request, name=\"profile/invitation.html\", context={ \"user\": user, \"doc\": data}\n",
" )"
@ -4341,9 +4341,16 @@
"outputs": [],
"source": [
"@app.post('/api/invitation/accept/{invitations_id}')\n",
"async def invitation_accept(invitations_id:str):\n",
" await accept_invitations(invitations_id)\n",
" return {'ok': True}"
"async def invitation_accept(invitations_id: str, request: Request):\n",
" payload = await request.json()\n",
" posts_ids: List[str] = payload.get(\"posts\", [])\n",
"\n",
" # optional: валидация\n",
" if not isinstance(posts_ids, list):\n",
" posts_ids = []\n",
"\n",
" await accept_invitations(invitations_id, posts_ids)\n",
" return {'ok': True}\n"
]
},
{

12
main.py
View File

@ -3368,10 +3368,18 @@ async def profile_invitation(
)
@app.post('/api/invitation/accept/{invitations_id}')
async def invitation_accept(invitations_id:str):
await accept_invitations(invitations_id)
async def invitation_accept(invitations_id: str, request: Request):
payload = await request.json()
posts_ids: List[str] = payload.get("posts", [])
# optional: валидация
if not isinstance(posts_ids, list):
posts_ids = []
await accept_invitations(invitations_id, posts_ids)
return {'ok': True}
@app.get('/profile/delivery/{post_id}')
async def profile_delivery_history_post(request: Request, post_id:str, user: Dict = Security(get_current_user)):
data = await delivery_collection.find({'post_id': post_id, "$or": [

View File

@ -636,13 +636,35 @@
"metadata": {},
"outputs": [],
"source": [
"async def accept_invitations(invitations_id):\n",
"from typing import List\n",
"from bson import ObjectId\n",
"\n",
"async def accept_invitations(invitations_id: str, posts_ids: List[str]):\n",
" invitation = await invitations_collection.find_one_and_update(\n",
" {\"_id\": ObjectId(invitations_id)},\n",
" {\"$set\": {\"accept\": True}},\n",
" return_document=True, \n",
" return_document=True,\n",
" )\n",
" delivery_collection.update_many({'post_id': {'$in': [str(doc['_id']) for doc in invitation.get('posts', [])]}}, {'$set':{'status': 'Ожидает отправки'}})\n",
"\n",
" invitation_posts = invitation.get('posts', []) or []\n",
" invitation_post_ids = [str(doc['_id']) for doc in invitation_posts]\n",
"\n",
" selected_set = set(str(x) for x in posts_ids)\n",
" selected_ids = [pid for pid in invitation_post_ids if pid in selected_set]\n",
" other_ids = [pid for pid in invitation_post_ids if pid not in selected_set]\n",
"\n",
" if selected_ids:\n",
" await delivery_collection.update_many(\n",
" {'post_id': {'$in': selected_ids}},\n",
" {'$set': {'status': 'Ожидает отправки'}}\n",
" )\n",
"\n",
" if other_ids:\n",
" await delivery_collection.update_many(\n",
" {'post_id': {'$in': other_ids}},\n",
" {'$set': {'status': 'Приглашение откланено'}} # как вы написали\n",
" )\n",
"\n",
" await notify_in_profile(NotifyItem(\n",
" user_id=invitation.get('exhibition',{}).get(\"user\",{}).get('_id'),\n",
" type_item='c',\n",

View File

@ -487,13 +487,35 @@ async def get_sender(post_id):
delivery = delivery[0] if delivery else {}
return delivery.get('receiver')
async def accept_invitations(invitations_id):
from typing import List
from bson import ObjectId
async def accept_invitations(invitations_id: str, posts_ids: List[str]):
invitation = await invitations_collection.find_one_and_update(
{"_id": ObjectId(invitations_id)},
{"$set": {"accept": True}},
return_document=True,
)
delivery_collection.update_many({'post_id': {'$in': [str(doc['_id']) for doc in invitation.get('posts', [])]}}, {'$set':{'status': 'Ожидает отправки'}})
invitation_posts = invitation.get('posts', []) or []
invitation_post_ids = [str(doc['_id']) for doc in invitation_posts]
selected_set = set(str(x) for x in posts_ids)
selected_ids = [pid for pid in invitation_post_ids if pid in selected_set]
other_ids = [pid for pid in invitation_post_ids if pid not in selected_set]
if selected_ids:
await delivery_collection.update_many(
{'post_id': {'$in': selected_ids}},
{'$set': {'status': 'Ожидает отправки'}}
)
if other_ids:
await delivery_collection.update_many(
{'post_id': {'$in': other_ids}},
{'$set': {'status': 'Приглашение откланено'}} # как вы написали
)
await notify_in_profile(NotifyItem(
user_id=invitation.get('exhibition',{}).get("user",{}).get('_id'),
type_item='c',

View File

@ -7,129 +7,256 @@
{% block title %}Приглашения{% endblock %}
{% macro render_post(doc) %}
<figure class="c_4b1hy b_uu2ub">
<img class="b_1fvkt" src="/b/posts/{{doc.medias[0]}}">
<figcaption class="c_3g8gh b_pvw5a">
<div class="b_thlt1_2">
<span class="b_5dr47_2">Выберите картину</span>
</div>
<div class="b_thlt1" style="display:none;">
<span class="b_5dr47">Картина выбрана</span>
</div>
<h2 class="c_9hvtd b_f5fb2">{{doc.title}}</h2>
<label class="offer-label">
<input
type="checkbox"
class="offer-checkbox"
data-post-id="{{ doc._id }}"
onchange="selectPost(this)"
>
<span class="offer-text">Выбрать</span>
</label>
<p class="b_6spaf">...</p>
</figcaption>
</figure>
{% endmacro %}
{% block content %}
{{ header.section(user) }}
<section class="c_dg3k4">
<div class="c_gtoe9">
{{ profile_card.profile_card(user) }}
<div class="c_ru432">
{{ profile_nav.profile_nav(user, 'invitation') }}
<div class="c_tihtk" id="main">
<article class="c_9fgdh b_ax8vz" id="l{{doc._id}}">
<div class="c_z3dpx b_73p10">
<div class="b_vabj9_2">
<span class="b_0jst1_2">{{doc.type}}</span>
</div>
<header class="c_m876y b_9xtz9">
<h3 class="c_hysjg b_8f3uh">{{ doc.title }}</h3>
</header>
{% if doc.get('type') == 'Выставка' %}
<p class="c_2fr39 b_tfnz2">{{doc.get('exhibition').title }}</p>
<p>Место проведения: {{ doc.get('exhibition').get('place') }}</p>
<div class="b_otttb">
<span class="c_2fr39 b_tfnz2">С {{ ( doc.get('exhibition').datetime_start.strftime('%d.%m.%Y')) if doc.get('exhibition').datetime_start
else ''}}</span>
<span class="c_2fr39 b_tfnz2">По {{ ( doc.get('exhibition').date_finish.strftime('%d.%m.%Y')) if doc.get('exhibition').date_finish else
''}}</span>
</div>
<a class="btn" href="{% if doc.get('exhibition') and doc.get('exhibition').get('tizer_link') %}{{doc.get('exhibition').tizer_link}}{% else %}/b/competition/{{ doc.get('exhibition').tizer_file_id }}{% endif %}" style="width: 100%;">Релиз выставки</a>
<a class="btn" href="{% if doc.get('exhibition') and doc.get('exhibition').get('rules_link') %}{{doc.get('exhibition').rules_link}}{% else %}/b/competition/{{ doc.get('exhibition').rules_file_id }}{% endif %}" style="width: 100%;">Условия выставки</a>
{% if doc.get('accept') == False %}
<button onclick="accept_inv('{{doc._id}}')" class="btn" href="/profile/delivery#main" style="width: 100%; box-sizing: border-box;">Принять условия</button>
{% else %}
{% endif %}
{% else %}
<p class="c_2fr39 b_tfnz2">"{{ doc.get('item') }}" просьба связаться с организатором для обсуждения дальнейших действий</p>
{% endif %}
<!-- <p class="c_sihck b_s6ool">От</p> -->
{% set user = doc.get('user') %}
<div class="c_dbbe4 b_otttb">
{% if user %}
<img class="c_pm80w b_a68fq" src="/a/{{user._id}}" alt="{{ user.username | e }}" crossorigin="anonymous" fetchpriority="high" loading="eager">
<div class="c_4402p b_ntazj">
<p class="c_kvah4 b_ghosy">{{ user.username | e }}</p>
<div class="c_gtoe9">
{{ profile_card.profile_card(user) }}
<div class="c_ru432">
{{ profile_nav.profile_nav(user, 'invitation') }}
<div class="c_tihtk" id="main">
<article class="c_9fgdh b_ax8vz" id="l{{doc._id}}">
<div class="c_z3dpx b_73p10">
<div class="b_vabj9_2">
<span class="b_0jst1_2">{{doc.type}}</span>
</div>
{% endif %}
</div>
<div class="menua">
<a class="icona" href="tel:{{user.phone.split(',')[-1].strip()}}"><svg xmlns="http://www.w3.org/2000/svg" height="24px"
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
<path
d="M162-120q-18 0-30-12t-12-30v-162q0-13 9-23.5t23-14.5l138-28q14-2 28.5 2.5T342-374l94 94q38-22 72-48.5t65-57.5q33-32 60.5-66.5T681-524l-97-98q-8-8-11-19t-1-27l26-140q2-13 13-22.5t25-9.5h162q18 0 30 12t12 30q0 125-54.5 247T631-329Q531-229 409-174.5T162-120Zm556-480q17-39 26-79t14-81h-88l-18 94 66 66ZM360-244l-66-66-94 20v88q41-3 81-14t79-28Zm358-356ZM360-244Z" />
</svg>
<span>{{ user.phone.split(',')[-1].strip() }}</span>
</a>
<a class="icona" href="mailto:{{user.email}}"> <svg xmlns="http://www.w3.org/2000/svg" height="24px"
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
<path
d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480v58q0 59-40.5 100.5T740-280q-35 0-66-15t-52-43q-29 29-65.5 43.5T480-280q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480v58q0 26 17 44t43 18q26 0 43-18t17-44v-58q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93h200v80H480Zm85-315q35-35 35-85t-35-85q-35-35-85-35t-85 35q-35 35-35 85t35 85q35 35 85 35t85-35Z" />
</svg>
<span>{{user.email}}</span>
</a>
<div class="icona"><span>Написать</span></div>
<div class="icona">
<a class="icona" href="{% if user.social_vk %}https://vk.ru/im?sel={{user.social_vk.id}}{%else%}#{%endif%}">
<img src="/static/icons/vk.svg" height="40">
</a>
<a class="icona" href="https://telegram.me/{{user.phone.split(',')[-1].strip()}}">
<img src="/static/icons/tg.svg" height="40">
<!-- <span>Написать в ТГ</span> -->
</a>
<a class="icona" href="https://max.ru/{{user.phone.split(',')[-1].strip()}}">
<img src="/static/icons/max.svg" height="40" style="border-radius: 50% 50% 50% 30%;">
<!-- <span>Написать в MAX</span> -->
</a>
<a class="icona" href="https://wa.me/{{user.phone.split(',')[-1].strip()}}">
<img src="/static/icons/wapp.svg" height="40">
<!-- <span>Написать в WA</span> -->
</a>
</div>
</div>
<p class="c_drpqj b_mp1wb">{{ (doc._id.generation_time.strftime('%d.%m.%Y')) if doc._id else ''}}</p>
</div>
</article>
<header class="c_m876y b_9xtz9">
<h3 class="c_hysjg b_8f3uh">{{ doc.title }}</h3>
</header>
<p class="c_2fr39 b_tfnz2">{{doc.get('exhibition').title }}</p>
<p>Место проведения: {{ doc.get('exhibition').get('place') }}</p>
<div class="b_otttb">
<span class="c_2fr39 b_tfnz2">С {{ ( doc.get('exhibition').datetime_start.strftime('%d.%m.%Y')) if
doc.get('exhibition').datetime_start
else ''}}</span>
<span class="c_2fr39 b_tfnz2">По {{ ( doc.get('exhibition').date_finish.strftime('%d.%m.%Y')) if
doc.get('exhibition').date_finish else
''}}</span>
</div>
</div>
{{render_links(doc)}}
<p>Выбрано: <span id="lenSelected">0</span></p>
<button
onclick="accept_inv('{{doc._id}}')"
class="btn"
style="width: 100%; box-sizing: border-box;"
>
Принять условия
</button>
{% set user_contact = doc.get('user') %}
{{render_user_contacts(user_contact)}}
<p class="c_drpqj b_mp1wb">{{ (doc._id.generation_time.strftime('%d.%m.%Y')) if doc._id else ''}}</p>
</div>
</article>
{% for post in doc.get('posts')%}
{{render_post(post)}}
{% endfor %}
</div>
</div>
</div>
</section>
<script>
async function accept_inv(inv_id) {
try {
const res = await fetch(`/api/invitation/accept/${inv_id}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
const LS_KEY = 'selected_posts_ids';
function safeParseArray(raw) {
try {
const v = JSON.parse(raw);
if (!Array.isArray(v)) return [];
return v.map(String);
} catch {
return [];
}
}
function loadSelectedIds() {
const raw = localStorage.getItem(LS_KEY);
if (!raw) return [];
return safeParseArray(raw);
}
function saveSelectedIds(ids) {
localStorage.setItem(LS_KEY, JSON.stringify(ids.map(String)));
}
function updateSelectedCount() {
const el = document.getElementById('lenSelected');
if (!el) return;
el.textContent = String(loadSelectedIds().length);
}
function setStateUI(checkbox) {
const figure = checkbox && checkbox.closest ? checkbox.closest('figure') : null;
if (!figure) return;
const chooseBlock = figure.querySelector('.b_thlt1_2');
const selectedBlock = figure.querySelector('.b_thlt1');
const checked = !!checkbox.checked;
if (chooseBlock) chooseBlock.style.display = checked ? 'none' : '';
if (selectedBlock) selectedBlock.style.display = checked ? '' : 'none';
}
function setAllCheckboxesFromStorage() {
const selectedSet = new Set(loadSelectedIds());
const boxes = document.querySelectorAll('.offer-checkbox');
boxes.forEach(cb => {
const postId = String(cb.dataset.postId || '');
const isSelected = postId && selectedSet.has(postId);
cb.checked = isSelected;
setStateUI(cb);
});
if (res.ok) {
updateSelectedCount();
}
function selectPost(checkbox) {
if (!checkbox || !checkbox.dataset) return;
const postId = String(checkbox.dataset.postId || '');
if (!postId) return;
// делаем из текущего состояния множества (устойчиво к дублям и т.п.)
const ids = loadSelectedIds();
const set = new Set(ids);
if (checkbox.checked) set.add(postId);
else set.delete(postId);
const next = Array.from(set);
saveSelectedIds(next);
setStateUI(checkbox);
updateSelectedCount();
}
async function accept_inv(inv_id) {
const ids = loadSelectedIds();
if (!Array.isArray(ids) || ids.length === 0) {
showToast({ message: 'Выберите хотя бы одну картину', status: 'error' });
return;
}
try {
const res = await fetch(`/api/invitation/accept/${inv_id}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ posts: ids })
});
if (!res.ok) {
showToast({ message: 'Не удалось принять приглашение', status: 'error' });
return;
}
showToast({ message: 'Приглашение принято. Перенаправляем на страницу доставки' });
// на всякий случай: не удаляем localStorage сразу (если вдруг навигация сорвётся),
// но можно закомментировать следующую строку при необходимости
// localStorage.removeItem(LS_KEY);
setTimeout(() => {
window.location.href = '/profile/delivery#main';
}, 800);
} else {
showToast({ message: 'Не удалось принять приглашение', status: 'error' });
}
} catch (e) {
showToast({ message: 'Ошибка сети/сервера', status: 'error' });
}
}
</script>
} catch (e) {
showToast({ message: 'Ошибка сети/сервера', status: 'error' });
}
}
// загрузка состояния при открытии страницы
document.addEventListener('DOMContentLoaded', () => {
setAllCheckboxesFromStorage();
});
</script>
{{ footer.section(user) }}
{% endblock %}
{% macro render_user_contacts(user) %}
<div class="c_dbbe4 b_otttb">
{% if user %}
<img class="c_pm80w b_a68fq" src="/a/{{user._id}}" alt="{{ user.username | e }}" crossorigin="anonymous"
fetchpriority="high" loading="eager">
<div class="c_4402p b_ntazj">
<p class="c_kvah4 b_ghosy">{{ user.username | e }}</p>
</div>
{% endif %}
</div>
<div class="menua">
<a class="icona" href="tel:{{user.phone.split(',')[-1].strip()}}"><svg xmlns="http://www.w3.org/2000/svg"
height="24px" viewBox="0 -960 960 960" width="24px" fill="#5F1798">
<path
d="M162-120q-18 0-30-12t-12-30v-162q0-13 9-23.5t23-14.5l138-28q14-2 28.5 2.5T342-374l94 94q38-22 72-48.5t65-57.5q33-32 60.5-66.5T681-524l-97-98q-8-8-11-19t-1-27l26-140q2-13 13-22.5t25-9.5h162q18 0 30 12t12 30q0 125-54.5 247T631-329Q531-229 409-174.5T162-120Zm556-480q17-39 26-79t14-81h-88l-18 94 66 66ZM360-244l-66-66-94 20v88q41-3 81-14t79-28Zm358-356ZM360-244Z" />
</svg>
<span>{{ user.phone.split(',')[-1].strip() }}</span>
</a>
<a class="icona" href="mailto:{{user.email}}"> <svg xmlns="http://www.w3.org/2000/svg" height="24px"
viewBox="0 -960 960 960" width="24px" fill="#5F1798">
<path
d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480v58q0 59-40.5 100.5T740-280q-35 0-66-15t-52-43q-29 29-65.5 43.5T480-280q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480v58q0 26 17 44t43 18q26 0 43-18t17-44v-58q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93h200v80H480Zm85-315q35-35 35-85t-35-85q-35-35-85-35t-85 35q-35 35-35 85t35 85q35 35 85 35t85-35Z" />
</svg>
<span>{{user.email}}</span>
</a>
<div class="icona"><span>Написать</span></div>
<div class="icona">
<a class="icona" href="{% if user.social_vk %}https://vk.ru/im?sel={{user.social_vk.id}}{%else%}#{%endif%}">
<img src="/static/icons/vk.svg" height="40">
</a>
<a class="icona" href="https://telegram.me/{{user.phone.split(',')[-1].strip()}}">
<img src="/static/icons/tg.svg" height="40">
<!-- <span>Написать в ТГ</span> -->
</a>
<a class="icona" href="https://max.ru/{{user.phone.split(',')[-1].strip()}}">
<img src="/static/icons/max.svg" height="40" style="border-radius: 50% 50% 50% 30%;">
<!-- <span>Написать в MAX</span> -->
</a>
<a class="icona" href="https://wa.me/{{user.phone.split(',')[-1].strip()}}">
<img src="/static/icons/wapp.svg" height="40">
<!-- <span>Написать в WA</span> -->
</a>
</div>
</div>
{% endmacro %}
{% macro render_links(doc) %}
<a class="btn" href="{% if doc.get('exhibition') and doc.get('exhibition').get('tizer_link') %}{{doc.get('exhibition').tizer_link}}{% else %}/b/competition/{{ doc.get('exhibition').tizer_file_id }}{% endif %}" style="width: 100%;">Релиз выставки</a>
<a class="btn" href="{% if doc.get('exhibition') and doc.get('exhibition').get('rules_link') %}{{doc.get('exhibition').rules_link}}{% else %}/b/competition/{{ doc.get('exhibition').rules_file_id }}{% endif %}" style="width: 100%;">Условия выставки</a>
{% endmacro %}
{% block head %}
{{ header.style() }}
{{ profile_nav.style() }}
@ -218,6 +345,73 @@ picture>img{ width: 100%; object-fit: scale-down; }
.c_iiehk { align-items: flex-end; border-radius: 5px; display: flex; flex-direction: column; gap: 20px; width: 310px; }
.c_nnsh6>a>img{display: none;}
}</style>
<style type="text/css">
.b_thlt1 { align-items: center; background: rgba(14, 214, 70, 0.20); border-radius: 30px; display: flex; justify-content: center; padding: 1.5px 10px; }
.b_5dr47 { color: #0ED646; font-family: Inter; font-size: 12px; font-style: normal; font-weight: 700; line-height: normal; }
.b_thlt1_2 { align-items: center; background: rgba(95, 23, 152, 0.20); border-radius: 30px; display: flex; justify-content: center; padding: 1.5px 10px; }
.b_5dr47_2 { color: #5F1798; font-family: Inter; font-size: 12px; font-style: normal; font-weight: 700; line-height: normal; }
.b_6spaf {
color: #5F1798;
font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: normal;
}
.b_qla2q {
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
color: #000;
display: -webkit-box;
font-family: Inter;
font-size: 13px;
font-style: normal;
font-weight: 400;
line-height: normal;
overflow: hidden;
text-overflow: ellipsis;
}
.b_uu2ub { align-items: flex-start; background: #FDFAFF; border-radius: 5px; border: 1px solid #5F1798; box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.25), 0 4px 20px 0 rgba(0, 0, 0, 0.20); display: flex; flex-direction: column; width: 335px; }
.b_1fvkt { align-self: stretch; border-radius: 5px; flex-shrink: 0; }
.b_pvw5a { gap: 7px;align-items: flex-start; align-self: stretch; display: flex; flex-direction: column; flex: 1 0 0; justify-content: space-between; padding: 10px 20px 37px 20px; }
.b_xz6em { align-items: center; align-self: stretch; display: flex; gap: 13px; }
.b_ob59y { border-radius: 1em; height: 70px; min-width: 70px; max-width: 150px; vertical-align: top; object-fit: cover;}
.b_ffruz { align-items: flex-start; display: flex; flex-direction: column; flex: 1 0 0; justify-content: center; }
.b_09est { color: #000; font-family: Inter; font-size: 15px; font-style: normal; font-weight: 700; line-height: normal; }
.b_wy3rt {
align-items: center;
background: #5F1798;
border-radius: 5px;
display: flex;
justify-content: center;
padding: 15px 0;
width: 100%;
}
.b_bvl0d {
color: #FFF;
font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: normal;
}
/* Mobile */
@media (max-width: 699px) {
.c_3g8gh { align-items: flex-start; align-self: stretch; display: flex; flex-direction: column; flex-shrink: 0; justify-content: space-between; padding: 10px 20px 37px 20px; }
.c_4b1hy { align-items: flex-start; background: #FDFAFF; border-radius: 5px; border: 1px solid #5F1798; box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.25), 0 4px 20px 0 rgba(0, 0, 0, 0.20); display: flex; flex-direction: column; width: 335px; }
.c_mrl59 { align-items: center; background: #5F1798; border-radius: 25px; bottom: -15px; display: flex; height: 50px; justify-content: center; position: absolute; right: -15px; width: 50px; }
}
/* Tablet */
@media (min-width: 700px) and (max-width: 900px) {
.c_iiehk { align-items: center; border-radius: 5px; display: flex; flex-direction: column; gap: 20px; width: 335px; }
.c_nnsh6>a>img{display: none;}
}
/* Desktop */
@media (min-width: 901px) {
.c_iiehk { align-items: flex-end; border-radius: 5px; display: flex; flex-direction: column; gap: 20px; width: 310px; }
.c_nnsh6>a>img{display: none;}
}</style>
{{ footer.style() }}
{% endblock %}