Jump to content
Dr. Rolex

jQuery/Ajax Dynamic Checkout for osCommerce 2.3.3

Recommended Posts

also the if someone tries to change the shipping address and then clicks continue, the checkout_shipping page becomes blank and also the checkout_payment page does not show up.

 

could u please look into this, or is it i am only getting this error

Share this post


Link to post
Share on other sites

hi

u did not list the changes in the file login.php in the user manual

 

regards

 

sam

 

Hi! Ok, don't worry.

 

In ./login.php find around line 85:

require(DIR_WS_INCLUDES . 'template_top.php');

Replace with:

if ( $_SERVER['HTTP_X_REQUESTED_WITH'] != 'XMLHttpRequest' )
{
require(DIR_WS_INCLUDES . 'template_top.php');
}

Find around line 134:

<?php
require(DIR_WS_INCLUDES . 'template_bottom.php');
require(DIR_WS_INCLUDES . 'application_bottom.php');
?>

Replace with:

<?php
if ( $_SERVER['HTTP_X_REQUESTED_WITH'] != 'XMLHttpRequest' )
{
require(DIR_WS_INCLUDES . 'template_bottom.php');
require(DIR_WS_INCLUDES . 'application_bottom.php');
}
?>

 

Find the following code around line 118 in Step #5 - in ./checkout_payment_address.php there are no details

You can skip this step, it's just an empty template which I forgot to remove.

 

Regarding the other errors, my guess is that they are either CSS errors or Ajax errors.

Could you open the Chrome Javascript console (View => Developer => Javascript Console) and see if you get any error messages when you try to checkout.

 

You can also, after the page have gone blank, go to the "Elements" tab in Google Developer Toolbar and see if you can find the relevant data there (as in the data that should be displayed on the screen). The problem might just be that its still hidden with CSS style "display:none;" or "visibility:hidden;".

 

If you have a link to your site, then I can check it for you.

Share this post


Link to post
Share on other sites

I have got the displaying part sorted. the only problem i have now is paypal. when i choose the paypal payment option, it goes blank. i will try your suggestions and send u the details.

Share this post


Link to post
Share on other sites

Nice work, Dr. Rolex

 

Loving this addon!! Thank you very much :thumbsup:

 

I do have one small problem though with the payment information window. After Pressing continue I get a popup saying I must select a payment method; my store only offers electronic bank transfer so there's nothing to select

 

How do I modify checkout payment to continue when there is only one default payment method?

 

Thanks again

Share this post


Link to post
Share on other sites

Oh and something else, is there a way to change the slide effect? The sideways one makes me feel a little sick :P

 

Thanks

 

Yes, you can change it easily to any of the standard jQuery effect and also any of the easing effects. Find these lines in ./ext/modules/jquery.checkout.engine.js, found around line 216-217, 248-249 and 306-307:

 

/* Slide to next fieldset with style */
next_fs.toggle("slide", { direction: "right", easing: 'easeInOutBack' }, 2000);
current_fs.toggle("slide", { direction: "left", easing: 'easeInOutBack' }, 2000);

The last part '2000' is the animation time in milliseconds.

 

For example, if you want a fadeOut/fadeIn effect instead which I guess will not mess with your sea sickness? :=)

Replace the code above to this:

/* Slide to next fieldset with style */
// next_fs.toggle("slide", { direction: "right", easing: 'easeInOutBack' }, 2000);
// current_fs.toggle("slide", { direction: "left", easing: 'easeInOutBack' }, 2000);

next_fs.parent().fadeOut('2000');
current_fs.parent().fadeIn('2000');

 

 

Look here for alternatives: http://api.jquery.com/category/effects/

Look here for easing alternatives: http://gsgd.co.uk/sandbox/jquery/easing/

 

.. How do I modify checkout payment to continue when there is only one default payment method? ..

 

Find this code in the jquery.checkout.engine.js file, around line 197:

current_fs = $( event.target ).closest('fieldset');
if (current_fs.find('input[name=payment]:checked').length == 0 && current_fs.find('input[name=payment]').length > 0)

Replace with:

current_fs = $( event.target ).closest('fieldset');
if (current_fs.find('input[name=payment]:checked').length == 0 && current_fs.find('input[name=payment]').length >= 2)

 

 

I have got the displaying part sorted. the only problem i have now is paypal. when i choose the paypal payment option, it goes blank. i will try your suggestions and send u the details.

 

Since I don't use paypal myself, I'm a bit uncertain on how it's supposed to work. But I'll check into this when I have a bit more time, it shouldn't be too hard to fix.

Share this post


Link to post
Share on other sites

For those that want automatic capitalization of the first character when customer enters firstname, lastname, address ..

 

In:

./checkout_shipping_address.php

./checkout_payment_address.php

 

Find the code below around line 357 -AND- 346:

</fieldset>

Add the following code ABOVE the code you found:


<script type="text/javascript">
/* Make first character uppercase when creating new address */
$(function() {
function formatString(string)
{
if (/^[a-ö].+$/.test(string))
var string = string.charAt(0).toUpperCase() + string.slice(1);
return string;
}

function validateString(name) {
$('input[name=' + name + ']').val(formatString($('input[name=' + name + ']').val()));
}

$('body').find('input[type=text]').change(function() {
var name = $(this).attr('name');
validateString(name);
});
});
</script>

 

This same code can probably be used in ./create_account.php as well as ./address_book_process.php. Try to add it just before </form> or perhaps at the bottom of the page.

Share this post


Link to post
Share on other sites

 

 

Yes, you can change it easily to any of the standard jQuery effect and also any of the easing effects. Find these lines in ./ext/modules/jquery.checkout.engine.js, found around line 216-217, 248-249 and 306-307:

 

/* Slide to next fieldset with style */
next_fs.toggle("slide", { direction: "right", easing: 'easeInOutBack' }, 2000);
current_fs.toggle("slide", { direction: "left", easing: 'easeInOutBack' }, 2000);

The last part '2000' is the animation time in milliseconds.

 

For example, if you want a fadeOut/fadeIn effect instead which I guess will not mess with your sea sickness? :=)

Replace the code above to this:

/* Slide to next fieldset with style */
// next_fs.toggle("slide", { direction: "right", easing: 'easeInOutBack' }, 2000);
// current_fs.toggle("slide", { direction: "left", easing: 'easeInOutBack' }, 2000);

next_fs.parent().fadeOut('2000');
current_fs.parent().fadeIn('2000');

 

 

Look here for alternatives: http://api.jquery.com/category/effects/

Look here for easing alternatives: http://gsgd.co.uk/sandbox/jquery/easing/

 

 

 

Find this code in the jquery.checkout.engine.js file, around line 197:

current_fs = $( event.target ).closest('fieldset');
if (current_fs.find('input[name=payment]:checked').length == 0 && current_fs.find('input[name=payment]').length > 0)

Replace with:

current_fs = $( event.target ).closest('fieldset');
if (current_fs.find('input[name=payment]:checked').length == 0 && current_fs.find('input[name=payment]').length >= 2)

 

 

 

 

Since I don't use paypal myself, I'm a bit uncertain on how it's supposed to work. But I'll check into this when I have a bit more time, it shouldn't be too hard to fix.

 

Thanks Dr. Rolex

 

I made the changes to the engine file and at first it didn't work (I kept on seeing the sliding effect), so I forced a couple of refreshes and eventually saw the fade out/in effect.

 

Unfortunately it doesn't go past the shipping page; it fades and the progress bar moves up but I still see my shipping options, any suggestions?

 

Thanks so much

Share this post


Link to post
Share on other sites

I have got the displaying part sorted. the only problem i have now is paypal. when i choose the paypal payment option, it goes blank. i will try your suggestions and send u the details.

 

Here's your solution to the paypal mess Mr. Pheludar:

 

In jquery.checkout.engine.php, around line 192 find this code:

/* Next */
$('body').on('click', '.next', function(event){
event.preventDefault();

current_fs = $( event.target ).closest('fieldset');
if (current_fs.find('input[name=payment]:checked').length == 0 && current_fs.find('input[name=payment]').length >= 2)
return(alert( $('#JS_ERROR_NO_PAYMENT_MODULE_SELECTED').html() ));

if(animating) return false;

Replace with:

/* Next */
$('body').on('click', '.next', function(event){
event.preventDefault();

current_fs = $( event.target ).closest('fieldset');
if (current_fs.find('input[name=payment]:checked').length == 0 && current_fs.find('input[name=payment]').length >= 2)
return(alert( $('#JS_ERROR_NO_PAYMENT_MODULE_SELECTED').html() ));

if(animating) return false;
if(current_fs.find('.moduleRowSelected').find('input[name=payment]:checked').val() == 'paypal_express') return $('form[name="checkout_payment"]').submit();

If you or somebody else have similar problems with a checkout process that goes to an external URL, then you can try to add the same line (the last line in the set, starting with current_fs.fin..) as the one above, but change the "paypal_express" to the name of the radio button of the alternative that you want.

Add the code just below or above the last line in the code above above.

 

Unfortunately it doesn't go past the shipping page; it fades and the progress bar moves up but I still see my shipping options, any suggestions?

I'll take a look at it, is it the fadeOut/fadeIn effect your want the most or do you have any other effect that you want more?

Share this post


Link to post
Share on other sites

Thanks Dr. Rolex

 

I made the changes to the engine file and at first it didn't work (I kept on seeing the sliding effect), so I forced a couple of refreshes and eventually saw the fade out/in effect.

 

Unfortunately it doesn't go past the shipping page; it fades and the progress bar moves up but I still see my shipping options, any suggestions?

 

Thanks so much

 

The problem was that I put .parent() there for some reason. Damn Mondays!

 

OK, here are two alternatives that you can try out. The first one will fadeIn/fadeOut synchronized, while the last one will wait with the fadeIn until the fadeOut is completed.

Change these lines:

next_fs.parent().fadeOut('2000');
current_fs.parent().fadeIn('2000');

To this:

current_fs.fadeOut('2000');
next_fs.fadeIn('2000');

 

- OR -

Change from this:

next_fs.parent().fadeOut('2000');
current_fs.parent().fadeIn('2000');

$(current_fs).promise().done(function(data, textStatus, jqXHR){

/* Animate the Progress Bar */

To this:

current_fs.fadeOut('2000');
$(current_fs).promise().done(function(data, textStatus, jqXHR){
next_fs.fadeIn('2000');

/* Animate the Progress Bar */
Edited by Dr. Rolex

Share this post


Link to post
Share on other sites

Almost there

 

I tried your first suggestion and Delivery, Payment, Checkout transition is working beautifully but the back button shows a blank page

 

I then tried your second suggestion and pressing back just shows the page I was on.

 

Thanks for all your help. This is definitely going into my live store when working

Share this post


Link to post
Share on other sites

Almost there

 

I tried your first suggestion and Delivery, Payment, Checkout transition is working beautifully but the back button shows a blank page

 

I then tried your second suggestion and pressing back just shows the page I was on.

 

Thanks for all your help. This is definitely going into my live store when working

 

Glad you liked it! :thumbsup:

 

You need to change these lines in the /* Previous */ and the /* Progressbar */ section, around line 252 and line 306:

Find:

previous_fs.toggle("slide", { direction: "left", easing: 'easeInOutBack' }, 2000);
current_fs.toggle("slide", { direction: "right", easing: 'easeInOutBack' }, 2000);

Replace with:

// previous_fs.toggle("slide", { direction: "left", easing: 'easeInOutBack' }, 2000);
// current_fs.toggle("slide", { direction: "right", easing: 'easeInOutBack' }, 2000);

current_fs.fadeOut('2000');
previous_fs.fadeIn('2000');

Share this post


Link to post
Share on other sites

Glad you liked it! :thumbsup:

 

You need to change these lines in the /* Previous */ and the /* Progressbar */ section, around line 252 and line 306:

Find:

previous_fs.toggle("slide", { direction: "left", easing: 'easeInOutBack' }, 2000);
current_fs.toggle("slide", { direction: "right", easing: 'easeInOutBack' }, 2000);

Replace with:

// previous_fs.toggle("slide", { direction: "left", easing: 'easeInOutBack' }, 2000);
// current_fs.toggle("slide", { direction: "right", easing: 'easeInOutBack' }, 2000);

current_fs.fadeOut('2000');
previous_fs.fadeIn('2000');

 

Thanks

 

I'll make the changes tonight and report back :)

Share this post


Link to post
Share on other sites

Thanks

 

I'll make the changes tonight and report back :)

 

It's working!!! :thumbsup:

 

Thanks so much, you've taken my website to a new level of awesomeness!

 

Going to try your info box addon soon

Share this post


Link to post
Share on other sites

It's working!!! :thumbsup:

 

Thanks so much, you've taken my website to a new level of awesomeness!

 

Going to try your info box addon soon

 

Ha ha, great!

 

I aim to make everything Ajax, including product_info.php, index.php, product_listing.php & perhaps some more pages. I'm using this myself right now and together with a caching function for the pages and some queries, the shop is really fast. You almost can't see the pages loading. :P

 

Number of requests on product_info.php when logged in is down to around 9 from 44 requests (on page reload) and queries is down to 5-10. When everything is optimized the only queries that will run is the who's online and session queries and that should be around 5 instead of around 35 (with header_tags set to ON).

 

I'm currently working with the same type of Ajax enabled mobile site with Swipe gestures. When I'm done & satisfied with both Add-On I will probably upload them for the rest of the community. This will for sure speed up your shop A LOT! :thumbsup:

Share this post


Link to post
Share on other sites

Ha ha, great!

 

I aim to make everything Ajax, including product_info.php, index.php, product_listing.php & perhaps some more pages. I'm using this myself right now and together with a caching function for the pages and some queries, the shop is really fast. You almost can't see the pages loading. :P

 

Number of requests on product_info.php when logged in is down to around 9 from 44 requests (on page reload) and queries is down to 5-10. When everything is optimized the only queries that will run is the who's online and session queries and that should be around 5 instead of around 35 (with header_tags set to ON).

 

I'm currently working with the same type of Ajax enabled mobile site with Swipe gestures. When I'm done & satisfied with both Add-On I will probably upload them for the rest of the community. This will for sure speed up your shop A LOT! :thumbsup:

 

Can't wait! :D

Share this post


Link to post
Share on other sites

Important update for those that want customers that use IE9 to be able to confirm their order. As it is now; nothing will happen when they press the Confirm Order button.

 

Forget about what I just wrote, I realized that it just concerned anyone using "Accept Terms of Use", which isn't included in this Add-On.

Since I have already wrote some instructions, I guess I can continue.

 

Complete the following steps if you want an "Accept Terms of Use" checkbox at checkout & if you want the confirm button to disappear when the customer have confirmed the order and instead display a spinning "Please wait.."-box to prevent those damn double orders from happening, complete the following steps.

 

I got this message for some reason when trying to POST this, so the instructions will be on 2 POSTS:

You have posted a message with more emoticons than this community allows. Please reduce the number of emoticons you've added to the message. :'(

 

 

in ./checkout_confirmation.php

Find:

<fieldset class="checkoutProcess checkout_confirmation" id="conf">

Replace with:

<fieldset class="checkoutProcess checkout_confirmation" id="conf">
<span style="display:none !important;" id="CONDITION_AGREEMENT_ERROR"><?php echo str_replace('\n', '', CONDITION_AGREEMENT_ERROR); ?></span>

Find:

echo tep_draw_form('checkout_confirmation', $form_action_url, 'post');

Replace with:

echo tep_draw_form('checkout_confirmation', $form_action_url, 'post', 'id="checkout_confirmation"');

Find:

<span class="buttonAction" id="confirm"><?php echo tep_draw_button(IMAGE_BUTTON_CONFIRM_ORDER, 'check', null, 'primary', array('params' => 'class="action-button"')); ?></span>

Replace with:

<span class="buttonAction" id="confirm"><?php echo tep_draw_button(IMAGE_BUTTON_CONFIRM_ORDER, 'check', null, 'primary', array('params' => 'class="action-button"', 'type' => 'submit')); ?></span>

Find:

</form>
</fieldset>
<?php
if ( $_SERVER['HTTP_X_REQUESTED_WITH'] != 'XMLHttpRequest' )
{
require(DIR_WS_INCLUDES . 'template_bottom.php');
require(DIR_WS_INCLUDES . 'application_bottom.php');
}
?>

Replace with:

</form>
<script type="text/javascript" src="ext/modules/engine/jquery.checkout.engine.js"></script>
</fieldset>
<?php
if ( $_SERVER['HTTP_X_REQUESTED_WITH'] != 'XMLHttpRequest' )
{
require(DIR_WS_INCLUDES . 'template_bottom.php');
require(DIR_WS_INCLUDES . 'application_bottom.php');
} else {
tep_exit();
}
?>

Find:

<?php
}
?>
<div class="contentText">
<div style="float: right;">
<?php
if (is_array($payment_modules->modules)) {
echo $payment_modules->process_button();
}
?>

Replace with:

<?php
}
?>
	 <table width="100%" class="" border="0" style="border-collapse: collapse">
	 <tr>
					 <td>
	 <table border="0" width="100%" cellspacing="0" cellpadding="0" style="border-collapse: collapse">
							 <tr class="infoBoxContents">
									 <td align="right" border="0" colspan="2">
							 <b><?php echo CONDITION_AGREEMENT; ?></b>
			 </td>
			 <td onclick="window.document.checkout_confirmation.agree.checked = !window.document.checkout_confirmation.agree.checked;" align="right" width="20px"><?php echo tep_draw_checkbox_field('agree','true', false, 'id="TermsAgree" onclick="window.document.checkout_confirmation.agree.checked = !window.document.checkout_confirmation.agree.checked;"'); ?></td>
							 </tr>
			 <tr class="infoBoxContents">
			 <td align="right" colspan="2">
			 <a href="javascript:void(0);" class="osx">
			 <u style="main"><u style="main"><?php echo CONDITIONS; ?></u>
			 </a>
			 </td>
									 </tr>
	 </table>
					 </td>
					 </tr>
					 <td><?php echo tep_draw_separator('pixel_trans.gif', '100%', '10'); ?></td>
					 </tr>
					 <tr>
					 <td><table border="0" width="100%" cellspacing="1" cellpadding="2" class="infoBox">
	 <!--msg box Spinning confirmation -->
	 <div id="order_submitted" class="modal2">
	 <div class="modal3 ui-corner-all"><p><strong><?php echo ORDER_LOADING; ?></strong></p> <p><?php echo tep_image('images/loading2.gif'); ?></p></div>
	 </div>
							 </tr>
					 </table></td>
					 </tr>
					 <tr>
					 <td><?php echo tep_draw_separator('pixel_trans.gif', '100%', '10'); ?></td>
					 </tr>
	 </table></form></td>
	 </tr>
			 </table>
			 <!-- modal content -->
<div id="osx-modal-content">
	 <div id="osx-modal-title"><?=CONDITIONS?></div>
	 <div class="close"><a href="#" class="simplemodal-close">x</a></div>
	 <div id="osx-modal-data" style="overflow:scroll;height:570px;">
	 <?=TEXT_INFORMATION?>
	 <p><button class="simplemodal-close"><?=TEXT_AGREE_CLOSE?></button> <span><?=TEXT_AGREE_PRESS?></span></p>
	 </div>
</div>
<div class="contentText">
	 <div style="float: right;">
<?php
if (is_array($payment_modules->modules)) {
echo $payment_modules->process_button();
}
?>

Share this post


Link to post
Share on other sites

Find in ./ext/modules/engine/jquery.checkout.engine.js:

$('#checkoutProcess')
.css('height', imgHeight);
});
/* Check new Address Form */
function check_form_optional(form_name) {
var form = form_name;
var firstname = form.elements['firstname'].value;
var lastname = form.elements['lastname'].value;
var street_address = form.elements['street_address'].value;
if (firstname == '' && lastname == '' && street_address == '') {
return true;
} else {
return check_form(form_name);
}
}

Replace with:

$('#confirm').click(function(event){
event.preventDefault();
check_agree();
return false;
});
function check_agree() {
	 if ($("#TermsAgree").prop("checked")){
	 $('#confirm').hide();
	 $('#order_submitted').fadeIn(300);
	 $('#checkout_confirmation').submit();
	 return true;
	 } else {
	 return(alert( $('#CONDITION_AGREEMENT_ERROR').html() ));
	 return false;
	 }
}
/* OSX Modal */
jQuery(function($){var OSX={container:null,init:function(){$('body').on('click','input.osx, a.osx',function(e){e.preventDefault();$("#osx-modal-content").modal({overlayId:'osx-overlay',containerId:'osx-container',closeHTML:null,minHeight:80,opacity:65,position:['0',],overlayClose:true,onOpen:OSX.open,onClose:OSX.close})})},open:function(d){var self=this;self.container=d.container[0];d.overlay.fadeIn('slow',function(){$("#osx-modal-content",self.container).show();var title=$("#osx-modal-title",self.container);title.show();d.container.slideDown('slow',function(){setTimeout(function(){var h=$("#osx-modal-data",self.container).height()+title.height()+20;d.container.animate({height:h},200,function(){$("div.close",self.container).show();$("#osx-modal-data",self.container).show()})},300)})})},close:function(d){var self=this;d.container.animate({top:"-"+(d.container.height()+20)},500,function(){self.close()})}};OSX.init()});
/* OSX Modal End */

Insert the following code above the code below in ./stylesheet.css:

.modal2 {
display: none;
position: fixed;
z-index: 1000;
top:	 0;
left:	 0;
height:	 100%;
width:	 100%;
background: rgba( 255, 255, 255, .8 )
50% 50%
no-repeat;
}
/* Spinning loader at checkout */
.loading {
overflow: hidden;
display: block;
}
.modal3 {
position: fixed;
top: 50%;
left: 50%;
width: 200px;
height: 160px;
margin-top: -80px;
margin-left: -100px;
border: 1px solid #ccc;
background-color: #eee;
color: #000;
font: 16px/24px "Lucida Grande", Arial, sans-serif;
padding-bottom: 4px;
-moz-border-radius-bottomleft: 6px;
-webkit-border-bottom-left-radius: 6px;
-moz-border-radius-bottomright: 6px;
-webkit-border-bottom-right-radius: 6px;
border-radius: 0 0 6px 6px;
-moz-box-shadow: 0 0 64px #000;
-webkit-box-shadow: 0 0 64px #000;
overflow: hidden;
display: block;
text-align: center;
}
.modal3>p {
margin-top: 5px;
padding: 10px;
}
#osx-modal-content, #osx-modal-data {display:none;}
/* Overlay */
#osx-overlay {background-color:#000; cursor:wait;}
/* Container */
#osx-container {background-color:#eee; color:#000; font: 16px/24px "Lucida Grande",Arial,sans-serif; padding-bottom:4px; width:600px; -moz-border-radius-bottomleft:6px; -webkit-border-bottom-left-radius:6px; -moz-border-radius-bottomright:6px; -webkit-border-bottom-right-radius:6px; border-radius:0 0 6px 6px; -moz-box-shadow:0 0 64px #000; -webkit-box-shadow:0 0 64px #000;}
#osx-container a {color:#ddd;}
#osx-container #osx-modal-title {color:#000; background-color:#ddd; border-bottom:1px solid #ccc; font-weight:bold; padding:6px 8px; text-shadow:0 1px 0 #f4f4f4;}
#osx-container .close {display:none; position:absolute; right:0; top:0;}
#osx-container .close a {display:block; color:#777; font-weight:bold; padding:6px 12px 0; text-decoration:none; text-shadow:0 1px 0 #f4f4f4;}
#osx-container .close a:hover {color:#000;}
#osx-container #osx-modal-data {font-size:12px; padding:6px 12px;}
#osx-container h2 {margin:10px 0 6px;}
#osx-container p {margin-bottom:10px;}
#osx-container span {color:#777;}

Insert & modify definitions at bottom of file ./includes/languages/english.php:

/* Accept Terms Agree */
@[member='definedmedia'] ('CONDITION_AGREEMENT', 'I have read the terms of use and accept in full. ');
@[member='definedmedia'] ('CONDITIONS', 'Conditions and terms of use.');
@[member='definedmedia'] ('CONDITION_AGREEMENT_ERROR', 'Please read our terms of use, if you don\'t accept, your order will not be completed.');
@[member='definedmedia'] ('TEXT_AGREE_CLOSE', 'Close');
@[member='definedmedia'] ('TEXT_AGREE_PRESS', '(or press ESC to exit)');
@[member='definedmedia']('ORDER_LOADING', 'Please wait while your order is registered...');

Share this post


Link to post
Share on other sites

Hi Dr. Rolex

 

I'm almost ready to promote the Dynamic Checkout changes to my live store but IE8 doesn't work correctly; Other "style" changes I've applied don't work in IE8 so it's not your code

 

Any suggestions how to make older browsers more compatible?

 

Thanks so much

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×