Skip to content

Commit 05044cc

Browse files
authored
Merge pull request #2 from FosterCommerce/stephen/fix-restore-again
handle restore for user carts
2 parents ac8931c + 3c138f8 commit 05044cc

File tree

3 files changed

+200
-9
lines changed

3 files changed

+200
-9
lines changed

src/Plugin.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ public function init(): void
3636
{
3737
parent::init();
3838

39+
// Set the base template directory for the plugin
40+
Craft::setAlias('@klaviyo-connect-plus', $this->getBasePath());
41+
3942
$this->setComponents([
4043
'api' => \fostercommerce\klaviyoconnectplus\services\Api::class,
4144
'track' => \fostercommerce\klaviyoconnectplus\services\Track::class,

src/controllers/CartController.php

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,31 +41,59 @@ public function actionRestore(): Response
4141
throw new HttpException(400, 'Cart is empty');
4242
}
4343

44-
// Restore the cart using reflection (Commerce 5 workaround)
44+
// Get current user
45+
$currentUser = Craft::$app->getUser()->getIdentity();
46+
$currentUserId = $currentUser ? $currentUser->id : null;
47+
48+
// Check if cart belongs to a user account
49+
// If user is not logged in, or logged in as different user
50+
if ($order->customerId && (! $currentUserId || $order->customerId !== $currentUserId)) {
51+
// Show message page using CP template mode
52+
$loginPath = Craft::$app->getConfig()->getGeneral()->getLoginPath();
53+
$loginUrl = \craft\helpers\UrlHelper::url($loginPath, [
54+
'return' => Craft::$app->getRequest()->getAbsoluteUrl(),
55+
]);
56+
$view = Craft::$app->getView();
57+
$oldMode = $view->getTemplateMode();
58+
$view->setTemplateMode(\craft\web\View::TEMPLATE_MODE_CP);
59+
$html = $view->renderTemplate('klaviyo-connect-plus/login-required', [
60+
'loginUrl' => $loginUrl,
61+
'message' => Craft::t('klaviyo-connect-plus', 'This cart belongs to a user account. Please log in to view it.'),
62+
]);
63+
$view->setTemplateMode($oldMode);
64+
return $this->asRaw($html);
65+
}
66+
67+
// At this point, either:
68+
// - Cart has no customer (guest cart), OR
69+
// - Current user owns the cart
70+
71+
// Clear current cart
4572
$cartsService = $commerce->getCarts();
4673
$cartsService->forgetCart();
4774

75+
// Set session
76+
$session = Craft::$app->getSession();
77+
$session->set('commerce_cart', $order->number);
78+
79+
// Use reflection to set the cart
4880
try {
4981
$reflection = new \ReflectionClass($cartsService);
5082
$cartProperty = $reflection->getProperty('_cart');
5183
$cartProperty->setAccessible(true);
5284
$cartProperty->setValue($cartsService, $order);
53-
54-
$session = Craft::$app->getSession();
55-
$session->set('commerce_cart', $order->number);
56-
57-
$session->setNotice(Craft::t('klaviyo-connect-plus', 'Your cart has been restored.'));
5885
} catch (\Exception $exception) {
59-
Craft::error('Failed to restore cart: ' . $exception->getMessage(), 'klaviyo-connect-plus');
60-
throw new HttpException(500, 'Failed to restore cart');
86+
Craft::error('Reflection failed: ' . $exception->getMessage(), 'klaviyo-connect-plus');
6187
}
6288

89+
$session->setNotice(Craft::t('klaviyo-connect-plus', 'Your cart has been restored.'));
90+
6391
/** @var Settings $settings */
6492
$settings = Plugin::getInstance()->getSettings();
6593
$cartUrl = $settings->cartUrl;
6694

6795
if ((string) $cartUrl === '') {
68-
throw new HttpException(400, 'Cart URL is required. Configure it in Settings -> Klaviyo Connect Plus -> Cart URL');
96+
throw new HttpException(400, 'Cart URL is required.');
6997
}
7098

7199
return $this->redirect($cartUrl);

src/templates/login-required.twig

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Login Required</title>
7+
<style>
8+
* {
9+
margin: 0;
10+
padding: 0;
11+
box-sizing: border-box;
12+
}
13+
body {
14+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
15+
background: linear-gradient(135deg, #1a1d29 0%, #2d3748 50%, #3d5a80 100%);
16+
min-height: 100vh;
17+
display: flex;
18+
align-items: center;
19+
justify-content: center;
20+
padding: 20px;
21+
position: relative;
22+
overflow: hidden;
23+
}
24+
body::before {
25+
content: '';
26+
position: absolute;
27+
width: 500px;
28+
height: 500px;
29+
background: radial-gradient(circle, rgba(197, 167, 119, 0.08) 0%, transparent 70%);
30+
top: -250px;
31+
right: -250px;
32+
border-radius: 50%;
33+
}
34+
body::after {
35+
content: '';
36+
position: absolute;
37+
width: 600px;
38+
height: 600px;
39+
background: radial-gradient(circle, rgba(197, 167, 119, 0.05) 0%, transparent 70%);
40+
bottom: -300px;
41+
left: -300px;
42+
border-radius: 50%;
43+
}
44+
.container {
45+
background: rgba(255, 255, 255, 0.98);
46+
border-radius: 16px;
47+
box-shadow: 0 25px 80px rgba(0, 0, 0, 0.4);
48+
max-width: 500px;
49+
width: 100%;
50+
padding: 48px;
51+
text-align: center;
52+
position: relative;
53+
z-index: 1;
54+
backdrop-filter: blur(10px);
55+
}
56+
.icon {
57+
width: 80px;
58+
height: 80px;
59+
background: linear-gradient(135deg, #c5a777 0%, #a88f65 100%);
60+
border-radius: 50%;
61+
display: flex;
62+
align-items: center;
63+
justify-content: center;
64+
margin: 0 auto 28px;
65+
box-shadow: 0 8px 24px rgba(197, 167, 119, 0.3);
66+
}
67+
.icon svg {
68+
width: 40px;
69+
height: 40px;
70+
color: white;
71+
}
72+
h1 {
73+
font-size: 28px;
74+
font-weight: 700;
75+
color: #1a1d29;
76+
margin-bottom: 16px;
77+
letter-spacing: -0.5px;
78+
}
79+
p {
80+
font-size: 17px;
81+
color: #4a5568;
82+
line-height: 1.7;
83+
margin-bottom: 36px;
84+
}
85+
.button {
86+
display: inline-block;
87+
background: linear-gradient(135deg, #c5a777 0%, #a88f65 100%);
88+
color: white;
89+
text-decoration: none;
90+
padding: 16px 40px;
91+
border-radius: 10px;
92+
font-weight: 600;
93+
font-size: 17px;
94+
transition: all 0.3s;
95+
box-shadow: 0 4px 16px rgba(197, 167, 119, 0.3);
96+
position: relative;
97+
overflow: hidden;
98+
}
99+
.button::before {
100+
content: '';
101+
position: absolute;
102+
top: 0;
103+
left: 0;
104+
width: 100%;
105+
height: 100%;
106+
background: linear-gradient(135deg, #d4b685 0%, #b69a73 100%);
107+
opacity: 0;
108+
transition: opacity 0.3s;
109+
}
110+
.button:hover::before {
111+
opacity: 1;
112+
}
113+
.button span {
114+
position: relative;
115+
z-index: 1;
116+
}
117+
.button:hover {
118+
transform: translateY(-2px);
119+
box-shadow: 0 8px 24px rgba(197, 167, 119, 0.4);
120+
}
121+
.badge {
122+
display: inline-flex;
123+
align-items: center;
124+
gap: 8px;
125+
background: #f0f4f8;
126+
color: #4a5568;
127+
padding: 8px 16px;
128+
border-radius: 20px;
129+
font-size: 14px;
130+
font-weight: 500;
131+
margin-top: 24px;
132+
}
133+
.badge svg {
134+
width: 16px;
135+
height: 16px;
136+
color: #c5a777;
137+
}
138+
</style>
139+
</head>
140+
<body>
141+
<div class="container">
142+
<div class="icon">
143+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
144+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"></path>
145+
</svg>
146+
</div>
147+
<h1>Login Required</h1>
148+
<p>{{ message }}</p>
149+
<a href="{{ loginUrl }}" class="button">
150+
<span>Log In to Continue</span>
151+
</a>
152+
<div class="badge">
153+
<svg fill="currentColor" viewBox="0 0 20 20">
154+
<path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd"/>
155+
</svg>
156+
Secure cart restoration
157+
</div>
158+
</div>
159+
</body>
160+
</html>

0 commit comments

Comments
 (0)