Merge pull request #464 from tiwariav/task/3704/my_settings

Task/3704 my settings page
This commit is contained in:
Arvind Tiwari 2017-09-07 22:36:09 +05:30 committed by GitHub
commit 3dca3a40ae
15 changed files with 389 additions and 16 deletions

View file

@ -344,8 +344,8 @@ msgstr "Rechnungsadresse"
msgid "Payment Method:" msgid "Payment Method:"
msgstr "Bezahlmethode" msgstr "Bezahlmethode"
msgid "ending" msgid "ending in"
msgstr "endend" msgstr "endend in"
msgid "Order summary" msgid "Order summary"
msgstr "Bestellungsübersicht" msgstr "Bestellungsübersicht"

View file

@ -50,7 +50,7 @@
<div class="col-xs-6"> <div class="col-xs-6">
<address> <address>
<strong>{% trans "Payment Method:"%}</strong><br> <strong>{% trans "Payment Method:"%}</strong><br>
{{cc_brand}} {% trans "ending" %} **** {{cc_last4}}<br> {{cc_brand}} {% trans "ending in" %} **** {{cc_last4}}<br>
{{request.session.user.email}} {{request.session.user.email}}
</address> </address>
</div> </div>

View file

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-09-02 03:08+0530\n" "POT-Creation-Date: 2017-09-05 00:59+0530\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -356,6 +356,32 @@ msgstr "Deine Kreditkartennummer"
msgid "Reset your password" msgid "Reset your password"
msgstr "Passwort zurücksetzen" msgstr "Passwort zurücksetzen"
msgid "UPDATE"
msgstr ""
msgid "Last"
msgstr ""
msgid "Type"
msgstr "Kartentyp"
msgid "REMOVE CARD"
msgstr "KARTE ENTFERNEN"
msgid "EDIT CARD"
msgstr "BEARBEITEN"
msgid "No Credit Cards Added"
msgstr "Es wurde keine Kreditkarte hinzugefügt"
msgid ""
"We are using <a href=\"https://stripe.com\">Stripe</a> for payment and do "
"not store your information in our database."
msgstr ""
"Wir nutzen <a href="
"\"https://stripe.com\" target=\"_blank\">Stripe</a> für die Bezahlung und "
"speichern keine Informationen in unserer Datenbank."
msgid "Add your public SSH key" msgid "Add your public SSH key"
msgstr "Füge deinen öffentlichen SSH-Key hinzu" msgstr "Füge deinen öffentlichen SSH-Key hinzu"
@ -513,6 +539,12 @@ msgid ""
"contact Data Center Light Support." "contact Data Center Light Support."
msgstr "Kontaktiere den Data Center Light Support." msgstr "Kontaktiere den Data Center Light Support."
#~ msgid "Add a new Card."
#~ msgstr "Neue Kreditkarte hinzufügen."
#~ msgid "You are not making any payment here."
#~ msgstr "Es wird noch keine Bezahlung vorgenommen"
#~ msgid "Your SSH Keys" #~ msgid "Your SSH Keys"
#~ msgstr "Deine SSH Keys" #~ msgstr "Deine SSH Keys"

View file

@ -12,6 +12,11 @@
max-width: 768px; max-width: 768px;
} }
.dashboard-container.wide {
padding-top: 90px;
max-width: 980px;
}
.content-dashboard{ .content-dashboard{
min-height: calc(100vh - 70px); min-height: calc(100vh - 70px);
width: 80%; width: 80%;
@ -241,6 +246,113 @@
transform: translate(-50%,-50%); transform: translate(-50%,-50%);
} }
.settings-container {
padding: 8px;
}
.settings-container h4 {
margin-bottom: 15px;
color: #333;
font-size: 14px;
}
.settings-container .card-expiry-element,
.settings-container .card-cvc-element {
padding: 0 15px;
}
.settings-container .card-cvc-element .my-input,
.settings-container .card-cvc-element label {
padding-left: 0;
}
.settings-container .stripe-payment-btn {
float: none;
position: static;
}
.settings-container h3 {
font-weight: bold;
}
.settings-container hr {
margin-top: 15px;
}
.settings-container .credit-card-details {
padding-bottom: 15px;
border-bottom: 1px solid #eee;
}
.settings-container .credit-card-details h5 {
font-weight: bold;
font-size: 16px;
}
.credit-card-form {
max-width: 360px;
}
.btn-wide {
min-width: 100px;
}
.caps-link {
font-weight: 600;
color: #8da4c0;
fill: #8da4c0;
padding: 8px 0;
display: block;
}
.caps-link:hover,
.caps-link:focus,
.caps-link:active {
color: #627388;
fill: #627388;
text-decoration: none;
}
.settings-container .credit-card-details-opt {
padding-top: 15px;
}
.caps-link .svg-img {
margin-right: 5px;
height: 13px;
position: relative;
top: 1px;
vertical-align: baseline;
}
.settings-container .caps-link {
font-size: 13px;
letter-spacing: 1.1px;
}
.settings-container .btn-vm-contact {
font-weight: 600;
font-size: 13px;
/* padding: 4px 15px; */
}
.btn-wide { .btn-wide {
min-width: 100px; min-width: 100px;
} }
.no-cards {
text-align: center;
color: #999;
padding: 15px;
background: rgba(0,0,0,0.02);
display: flex;
flex-direction: column;
height: 230px;
justify-content: center;
}
.no-cards h4 {
font-size: 24px;
}
.no-cards a {
color: #7ca3d0;
}

View file

@ -608,6 +608,7 @@ a.unlink:hover {
border: 1px solid #a1a1a1; border: 1px solid #a1a1a1;
border-radius: 3px; border-radius: 3px;
padding: 5px; padding: 5px;
margin-bottom: 15px;
} }
.card-warning-error { .card-warning-error {
border: 1px solid #EB4D5C; border: 1px solid #EB4D5C;
@ -765,12 +766,12 @@ a.unlink:hover {
@media (min-width: 768px) { @media (min-width: 768px) {
.dcl-billing { .dcl-billing {
padding-right: 50px; padding-right: 65px;
border-right: 1px solid #eee; border-right: 1px solid #eee;
} }
.dcl-creditcard { .dcl-creditcard {
padding-left: 50px; padding-left: 65px;
} }
.tbl-tot { .tbl-tot {

View file

@ -446,6 +446,11 @@
width: 34px; width: 34px;
vertical-align: middle; vertical-align: middle;
} }
.dashboard-title-thin .un-icon.wide {
height: 38px;
width: 38px;
margin-top: -6px;
}
.dashboard-subtitle { .dashboard-subtitle {
font-weight: 300; font-weight: 300;
@ -533,6 +538,11 @@
width: 22px; width: 22px;
margin-top: -3px; margin-top: -3px;
} }
.dashboard-title-thin .un-icon.wide {
height: 25px;
width: 25px;
margin-top: -5px;
}
.dashboard-subtitle p { .dashboard-subtitle p {
width: 200px; width: 200px;
} }

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
<g><path d="M185,150h630c19.3,0,35-15.7,35-35s-15.7-35-35-35H605c0-38.7-31.3-70-70-70h-70c-38.7,0-70,31.3-70,70H185c-19.3,0-35,15.7-35,35S165.7,150,185,150z"/><path d="M885,220h-69.9c-0.1,0-0.3,0-0.4,0H395.1c0,0-0.1,0-0.1,0H185.3c-0.1,0-0.2,0-0.3,0h-70c-19.3,0-35,15.7-35,35c0,19.3,15.7,35,35,35h39.9l100.5,670.2C258,977.3,272.7,990,290,990h139.9c0,0,0,0,0,0c0,0,0,0,0,0h140c0,0,0,0,0,0c0,0,0,0,0,0H710c17.3,0,32-12.7,34.6-29.8L845.1,290H885c19.3,0,35-15.7,35-35C920,235.7,904.3,220,885,220z M463.3,920l-31.5-630h136.4l-31.5,630H463.3z M225.6,290h136.1l31.5,630h-73.1L225.6,290z M679.9,920h-73.1l31.5-630h136.1L679.9,920z"/></g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -73,7 +73,6 @@ $( document ).ready(function() {
* Replace all SVG images with inline SVG * Replace all SVG images with inline SVG
*/ */
$('.svg-img').each(function() { $('.svg-img').each(function() {
console.log('asa')
var $img = $(this); var $img = $(this);
var imgID = $img.attr('id'); var imgID = $img.attr('id');
var imgClass = $img.attr('class'); var imgClass = $img.attr('class');

View file

@ -25,6 +25,8 @@
<link href="{% static 'hosting/css/commons.css' %}" rel="stylesheet"> <link href="{% static 'hosting/css/commons.css' %}" rel="stylesheet">
<link href="{% static 'hosting/css/virtual-machine.css' %}" rel="stylesheet"> <link href="{% static 'hosting/css/virtual-machine.css' %}" rel="stylesheet">
<link href="{% static 'hosting/css/dashboard.css' %}" rel="stylesheet"> <link href="{% static 'hosting/css/dashboard.css' %}" rel="stylesheet">
{% block css_extra %}
{% endblock css_extra %}
<!-- Custom Fonts --> <!-- Custom Fonts -->
<link href='//fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'> <link href='//fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'>

View file

@ -32,7 +32,7 @@
<img class="svg-img" src="{% static 'hosting/img/billing.svg' %}"> <img class="svg-img" src="{% static 'hosting/img/billing.svg' %}">
</div> </div>
</a> </a>
<a href="" class="hosting-dashboard-item"> <a href="{% url 'hosting:settings' %}" class="hosting-dashboard-item">
<h2>{% trans "My Settings" %}</h2> <h2>{% trans "My Settings" %}</h2>
<div class="hosting-dashboard-image"> <div class="hosting-dashboard-image">
<img class="svg-img" src="{% static 'hosting/img/dashboard_settings.svg' %}"> <img class="svg-img" src="{% static 'hosting/img/dashboard_settings.svg' %}">

View file

@ -1,9 +1,12 @@
{% extends "hosting/base_short.html" %} {% extends "hosting/base_short.html" %}
{% load staticfiles bootstrap3 i18n %} {% load staticfiles bootstrap3 i18n %}
{% block css_extra %}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/paymentfont/1.1.2/css/paymentfont.min.css"/>
{% endblock css_extra %}
{% block content %} {% block content %}
<!-- Credit card form --> <!-- Credit card form -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/paymentfont/1.1.2/css/paymentfont.min.css"/>
<div class="dcl-order-container"> <div class="dcl-order-container">
<div class="payment-container"> <div class="payment-container">
<div class="row"> <div class="row">

View file

@ -0,0 +1,149 @@
{% extends "hosting/base_short.html" %}
{% load staticfiles bootstrap3 i18n %}
{% block css_extra %}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/paymentfont/1.1.2/css/paymentfont.min.css"/>
{% endblock css_extra %}
{% block content %}
<div class="dashboard-container wide">
<div class="dashboard-container-head">
<h1 class="dashboard-title-thin"><img src="{% static 'hosting/img/dashboard_settings.svg' %}" class="un-icon wide"> {% trans "My Settings" %}</h1>
</div>
<!-- Credit card form -->
<div class="settings-container">
<div class="row">
<div class="col-sm-5 col-md-6 billing dcl-billing">
<h3>{%trans "Billing Address"%}</h3>
<hr>
<form role="form" id="billing-form" method="post" action="" novalidate>
{% for field in form %}
{% csrf_token %}
{% bootstrap_field field show_label=False type='fields' bound_css_class='' %}
{% endfor %}
<div class="form-group text-right">
<button type="submit" class="btn btn-vm-contact btn-wide">{% trans "UPDATE" %}</button>
</div>
</form>
</div>
<div class="col-sm-7 col-md-6 creditcard-box dcl-creditcard">
<h3>{%trans "Credit Card"%}</h3>
<hr>
<div>
{% if credit_card_data.last4 %}
<div class="credit-card-details">
<h5 class="billing-head">{% trans "Credit Card" %}</h5>
<h5 class="membership-lead">{% trans "Last" %} 4: *****{{credit_card_data.last4}}</h5>
<h5 class="membership-lead">{% trans "Type" %}: {{credit_card_data.cc_brand}}</h5>
{% comment %}
<div class="credit-card-details-opt">
<div class="row">
<div class="col-xs-6">
<a class="caps-link" href=""><img src="{% static 'hosting/img/delete.svg' %}" class="svg-img">{% trans "REMOVE CARD" %}</a>
</div>
<div class="col-xs-6 text-right">
<a class="btn btn-vm-contact" href="">{% trans "EDIT CARD" %}</a>
</div>
</div>
</div>
{% endcomment %}
</div>
{% else %}
<div class="no-cards">
<h4>{% trans "No Credit Cards Added" %}</h4>
<p>{% blocktrans %}We are using <a href="https://stripe.com">Stripe</a> for payment and do not store your information in our database.{% endblocktrans %}</p>
</div>
{% comment %}
<h4>{% trans "Add a new Card." %}</h4>
<p style="margin-bottom: 15px;">
{% blocktrans %}Please fill in your credit card information below. We are using <a href="https://stripe.com" target="_blank">Stripe</a> for payment and do not store your information in our database.{% endblocktrans %}
</p>
<form action="" id="payment-form-new" class="credit-card-form" method="POST">
<input type="hidden" name="token"/>
<div class="credit-card-goup">
<div class="card-element card-number-element">
<label>{%trans "Card Number" %}</label>
<div id="card-number-element" class="field my-input"></div>
</div>
<div class="row">
<div class="col-xs-6 col-sm-4 card-element card-expiry-element">
<label>{%trans "Expiry Date" %}</label>
<div id="card-expiry-element" class="field my-input"></div>
</div>
<div class="col-xs-6 col-sm-4 col-sm-offset-4 card-element card-cvc-element">
<label>{%trans "CVC" %}</label>
<div id="card-cvc-element" class="field my-input"></div>
</div>
</div>
<div class="card-element brand">
<label>{%trans "Card Type" %}</label>
<i class="pf pf-credit-card" id="brand-icon"></i>
</div>
</div>
<div id="card-errors" role="alert"></div>
<div>
{% if not messages and not form.non_field_errors %}
<p class="card-warning-content">
{% blocktrans %}You are not making any payment here.{% endblocktrans %}
</p>
{% endif %}
<div id='payment_error'>
{% for message in messages %}
{% if 'failed_payment' or 'make_charge_error' in message.tags %}
<ul class="list-unstyled"><li>
<p class="card-warning-content card-warning-error">{{ message|safe }}</p>
</li></ul>
{% endif %}
{% endfor %}
{% for error in form.non_field_errors %}
<p class="card-warning-content card-warning-error">
{{ error|escape }}
</p>
{% endfor %}
</div>
<div class="row">
<div class="col-xs-6 col-xs-offset-6 text-right">
<button class="btn btn-success stripe-payment-btn" type="submit">{%trans "Submit" %}
</button>
</div>
</div>
</div>
<div style="display:none;">
<p class="payment-errors"></p>
</div>
</form>
{% endcomment %}
{% endif %}
</div>
</div>
</div>
</div>
</div>
{% comment %}
<!-- stripe key data -->
{% if stripe_key %}
{% get_current_language as LANGUAGE_CODE %}
<script type="text/javascript">
window.processing_text = '{%trans "Processing" %}';
window.enter_your_card_text = '{%trans "Enter your credit card number" %}';
(function () {
window.stripeKey = "{{stripe_key}}";
window.current_lan = "{{LANGUAGE_CODE}}";
})();
</script>
{%endif%}
{% if credit_card_data.last4 and credit_card_data.cc_brand %}
<script type="text/javascript">
(function () {
window.hasCreditcard = true;
})();
</script>
{%endif%}
{% endcomment %}
{%endblock%}

View file

@ -1,6 +1,5 @@
from django.conf.urls import url from django.conf.urls import url
from django.contrib.auth import views as auth_views from django.contrib.auth import views as auth_views
from .views import ( from .views import (
DjangoHostingView, RailsHostingView, PaymentVMView, NodeJSHostingView, DjangoHostingView, RailsHostingView, PaymentVMView, NodeJSHostingView,
LoginView, SignupView, SignupValidateView, SignupValidatedView, IndexView, LoginView, SignupView, SignupValidateView, SignupValidatedView, IndexView,
@ -9,7 +8,8 @@ from .views import (
MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView, MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView,
HostingPricingView, CreateVirtualMachinesView, HostingBillListView, HostingPricingView, CreateVirtualMachinesView, HostingBillListView,
HostingBillDetailView, SSHKeyDeleteView, SSHKeyCreateView, SSHKeyListView, HostingBillDetailView, SSHKeyDeleteView, SSHKeyCreateView, SSHKeyListView,
SSHKeyChoiceView, DashboardView) SSHKeyChoiceView, DashboardView, SettingsView)
urlpatterns = [ urlpatterns = [
url(r'index/?$', IndexView.as_view(), name='index'), url(r'index/?$', IndexView.as_view(), name='index'),
@ -19,6 +19,7 @@ urlpatterns = [
url(r'rails/?$', RailsHostingView.as_view(), name='railshosting'), url(r'rails/?$', RailsHostingView.as_view(), name='railshosting'),
url(r'pricing/?$', HostingPricingView.as_view(), name='pricing'), url(r'pricing/?$', HostingPricingView.as_view(), name='pricing'),
url(r'payment/?$', PaymentVMView.as_view(), name='payment'), url(r'payment/?$', PaymentVMView.as_view(), name='payment'),
url(r'settings/?$', SettingsView.as_view(), name='settings'),
url(r'orders/?$', OrdersHostingListView.as_view(), name='orders'), url(r'orders/?$', OrdersHostingListView.as_view(), name='orders'),
url(r'orders/(?P<pk>\d+)/?$', OrdersHostingDetailView.as_view(), name='orders'), url(r'orders/(?P<pk>\d+)/?$', OrdersHostingDetailView.as_view(), name='orders'),
url(r'bills/?$', HostingBillListView.as_view(), name='bills'), url(r'bills/?$', HostingBillListView.as_view(), name='bills'),

View file

@ -487,6 +487,57 @@ class SSHKeyCreateView(LoginRequiredMixin, FormView):
return self.form_invalid(form) return self.form_invalid(form)
class SettingsView(LoginRequiredMixin, FormView):
template_name = "hosting/settings.html"
login_url = reverse_lazy('hosting:login')
form_class = BillingAddressForm
def get_form(self, form_class):
"""
Check if the user already saved contact details. If so, then show
the form populated with those details, to let user change them.
"""
return form_class(
instance=self.request.user.billing_addresses.first(),
**self.get_form_kwargs())
def get_context_data(self, **kwargs):
context = super(SettingsView, self).get_context_data(**kwargs)
# Get user
user = self.request.user
# Get user last order
last_hosting_order = HostingOrder.objects.filter(
customer__user=user).last()
# If user has already an hosting order, get the credit card data from
# it
if last_hosting_order:
credit_card_data = last_hosting_order.get_cc_data()
context.update({
'credit_card_data': credit_card_data if credit_card_data else None,
})
context.update({
'stripe_key': settings.STRIPE_API_PUBLIC_KEY
})
return context
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
billing_address_data = form.cleaned_data
billing_address_data.update({
'user': self.request.user.id
})
billing_address_user_form = UserBillingAddressForm(
instance=self.request.user.billing_addresses.first(),
data=billing_address_data)
billing_address_user_form.save()
return self.render_to_response(self.get_context_data())
else:
billing_address_data = form.cleaned_data
return self.form_invalid(form)
class PaymentVMView(LoginRequiredMixin, FormView): class PaymentVMView(LoginRequiredMixin, FormView):
template_name = 'hosting/payment.html' template_name = 'hosting/payment.html'
login_url = reverse_lazy('hosting:login') login_url = reverse_lazy('hosting:login')

View file

@ -41,7 +41,8 @@ class LoginFormMixin(forms.Form):
password = self.cleaned_data.get('password') password = self.cleaned_data.get('password')
is_auth = authenticate(email=email, password=password) is_auth = authenticate(email=email, password=password)
if not is_auth: if not is_auth:
raise forms.ValidationError("Your username and/or password were incorrect.") raise forms.ValidationError(
"Your username and/or password were incorrect.")
return self.cleaned_data return self.cleaned_data
def clean_email(self): def clean_email(self):
@ -101,7 +102,8 @@ class BillingAddressForm(forms.ModelForm):
class Meta: class Meta:
model = BillingAddress model = BillingAddress
fields = ['cardholder_name', 'street_address', 'city', 'postal_code', 'country'] fields = ['cardholder_name', 'street_address',
'city', 'postal_code', 'country']
labels = { labels = {
'cardholder_name': _('Cardholder Name'), 'cardholder_name': _('Cardholder Name'),
'street_address': _('Street Address'), 'street_address': _('Street Address'),
@ -117,8 +119,10 @@ class UserBillingAddressForm(forms.ModelForm):
class Meta: class Meta:
model = UserBillingAddress model = UserBillingAddress
fields = ['street_address', 'city', 'postal_code', 'country', 'user'] fields = ['cardholder_name', 'street_address',
'city', 'postal_code', 'country', 'user']
labels = { labels = {
'cardholder_name': _('Cardholder Name'),
'street_address': _('Street Building'), 'street_address': _('Street Building'),
'city': _('City'), 'city': _('City'),
'postal_code': _('Postal Code'), 'postal_code': _('Postal Code'),
@ -146,8 +150,10 @@ class ContactUsForm(forms.ModelForm):
} }
def send_email(self, email_to='info@digitalglarus.ch'): def send_email(self, email_to='info@digitalglarus.ch'):
text_content = render_to_string('emails/contact.txt', {'data': self.cleaned_data}) text_content = render_to_string(
html_content = render_to_string('emails/contact.html', {'data': self.cleaned_data}) 'emails/contact.txt', {'data': self.cleaned_data})
html_content = render_to_string(
'emails/contact.html', {'data': self.cleaned_data})
email = EmailMultiAlternatives('Subject', text_content) email = EmailMultiAlternatives('Subject', text_content)
email.attach_alternative(html_content, "text/html") email.attach_alternative(html_content, "text/html")
email.to = [email_to] email.to = [email_to]