More changes for db migration
This commit is contained in:
parent
de0284e48a
commit
889dc02945
33 changed files with 740 additions and 100 deletions
|
@ -5,6 +5,7 @@ import StatsD from 'statsy';
|
|||
import auth from './lib/auth';
|
||||
import * as user from './routes/user';
|
||||
import * as file from './routes/file';
|
||||
import * as pro from './routes/pro';
|
||||
import debugname from 'debug';
|
||||
const debug = debugname('hostr-api');
|
||||
|
||||
|
@ -64,10 +65,11 @@ router.get('/user/token', auth, user.token);
|
|||
router.get('/token', auth, user.token);
|
||||
router.get('/user/transaction', auth, user.transaction);
|
||||
router.post('/user/settings', auth, user.settings);
|
||||
router.post('/user/pro', auth, pro.create);
|
||||
router.delete('/user/pro', auth, pro.cancel);
|
||||
router.get('/file', auth, file.list);
|
||||
router.post('/file', auth, file.post);
|
||||
router.get('/file/:id', file.get);
|
||||
router.put('/file/:id', auth, file.put);
|
||||
router.delete('/file/:id', auth, file.del);
|
||||
router.delete('/file/:id', auth, file.del);
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ export default function* (next) {
|
|||
ip: remoteIp,
|
||||
successful: false,
|
||||
createdAt: {
|
||||
$gt: new Date(Math.ceil(Date.now()) - 600000),
|
||||
$gt: new Date(Date.now() - 600000),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -71,7 +71,7 @@ export default function* (next) {
|
|||
where: {
|
||||
userId: user.id,
|
||||
createdAt: {
|
||||
$gt: Math.ceil(Date.now() / 1000) - 86400,
|
||||
$gt: Date.now() - 86400000,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -54,7 +54,7 @@ export function* list() {
|
|||
const files = yield models.file.findAll({
|
||||
where: {
|
||||
userId: this.user.id,
|
||||
status: 'active',
|
||||
processed: true,
|
||||
},
|
||||
order: '"createdAt" DESC',
|
||||
offset,
|
||||
|
@ -70,9 +70,6 @@ export function* get() {
|
|||
const file = yield models.file.findOne({
|
||||
where: {
|
||||
id: this.params.id,
|
||||
status: {
|
||||
$in: ['active', 'uploading'],
|
||||
},
|
||||
},
|
||||
});
|
||||
this.assert(file, 404, '{"error": {"message": "File not found", "code": 604}}');
|
||||
|
@ -83,20 +80,6 @@ export function* get() {
|
|||
}
|
||||
|
||||
|
||||
export function* put() {
|
||||
if (this.request.body.trashed) {
|
||||
const file = yield models.file.findOne({
|
||||
where: {
|
||||
id: this.params.id,
|
||||
userId: this.user.id,
|
||||
},
|
||||
});
|
||||
file.status = this.request.body.trashed ? 'trashed' : 'active';
|
||||
yield file.save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function* del() {
|
||||
const file = yield models.file.findOne({
|
||||
where: {
|
||||
|
@ -105,8 +88,7 @@ export function* del() {
|
|||
},
|
||||
});
|
||||
this.assert(file, 401, '{"error": {"message": "File not found", "code": 604}}');
|
||||
file.status = 'deleted';
|
||||
yield file.save();
|
||||
yield file.destroy();
|
||||
const event = { type: 'file-deleted', data: { id: this.params.id } };
|
||||
yield this.redis.publish(`/file/${this.params.id}`, JSON.stringify(event));
|
||||
yield this.redis.publish(`/user/${this.user.id}`, JSON.stringify(event));
|
||||
|
|
85
api/routes/pro.js
Normal file
85
api/routes/pro.js
Normal file
|
@ -0,0 +1,85 @@
|
|||
import path from 'path';
|
||||
import views from 'co-views';
|
||||
const render = views(path.join(__dirname, '/../views'), { default: 'ejs' });
|
||||
import Stripe from 'stripe';
|
||||
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
|
||||
import sendgridInit from 'sendgrid';
|
||||
const sendgrid = sendgridInit(process.env.SENDGRID_KEY);
|
||||
|
||||
import models from '../../models';
|
||||
|
||||
const from = process.env.EMAIL_FROM;
|
||||
const fromname = process.env.EMAIL_NAME;
|
||||
|
||||
export function* create() {
|
||||
const stripeToken = this.request.body.stripeToken;
|
||||
|
||||
const ip = this.request.headers['x-real-ip'] || this.req.connection.remoteAddress;
|
||||
|
||||
const createCustomer = {
|
||||
card: stripeToken.id,
|
||||
plan: 'usd_monthly',
|
||||
email: this.user.email,
|
||||
};
|
||||
|
||||
const customer = yield stripe.customers.create(createCustomer);
|
||||
|
||||
this.assert(customer.subscription.status === 'active', 400, '{"status": "error"}');
|
||||
|
||||
delete customer.subscriptions;
|
||||
|
||||
const user = yield models.user.findById(this.user.id);
|
||||
user.plan = 'Pro';
|
||||
yield user.save();
|
||||
|
||||
const transaction = yield models.transaction.create({
|
||||
userId: this.user.id,
|
||||
amount: customer.subscription.plan.amount,
|
||||
description: customer.subscription.plan.name,
|
||||
data: customer,
|
||||
type: 'direct',
|
||||
ip,
|
||||
});
|
||||
|
||||
yield transaction.save();
|
||||
|
||||
this.user.plan = 'Pro';
|
||||
this.body = { status: 'active' };
|
||||
|
||||
const html = yield render('email/inlined/pro');
|
||||
const text = `Hey, thanks for upgrading to Hostr Pro!
|
||||
|
||||
You've signed up for Hostr Pro Monthly at $6/Month.
|
||||
|
||||
— Jonathan Cremin, Hostr Founder
|
||||
`;
|
||||
|
||||
const mail = new sendgrid.Email({
|
||||
to: this.user.email,
|
||||
subject: 'Hostr Pro',
|
||||
from,
|
||||
fromname,
|
||||
html,
|
||||
text,
|
||||
});
|
||||
mail.addCategory('pro-upgrade');
|
||||
sendgrid.send(mail);
|
||||
}
|
||||
|
||||
export function* cancel() {
|
||||
const user = yield models.user.findById(this.user.id);
|
||||
const transactions = yield user.getTransactions();
|
||||
const transaction = transactions[0];
|
||||
|
||||
yield stripe.customers.cancelSubscription(
|
||||
transaction.data.id,
|
||||
transaction.data.subscription.id,
|
||||
{ at_period_end: false }
|
||||
);
|
||||
|
||||
user.plan = 'Free';
|
||||
yield user.save();
|
||||
|
||||
this.user.plan = 'Free';
|
||||
this.body = { status: 'inactive' };
|
||||
}
|
|
@ -20,7 +20,11 @@ export function* token() {
|
|||
}
|
||||
|
||||
export function* transaction() {
|
||||
const transactions = yield models.transaction.findAll({ userId: this.user.id });
|
||||
const transactions = yield models.transaction.findAll({
|
||||
where: {
|
||||
userId: this.user.id,
|
||||
},
|
||||
});
|
||||
|
||||
this.body = transactions.map((item) => {
|
||||
return {
|
||||
|
|
101
api/views/email/inlined/pro.ejs
Normal file
101
api/views/email/inlined/pro.ejs
Normal file
|
@ -0,0 +1,101 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Hostr Pro</title>
|
||||
|
||||
</head>
|
||||
|
||||
<body style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; background: #f6f6f6; box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; height: 100%; line-height: 1.6; margin: 0; padding: 0; width: 100% !important" bgcolor="#f6f6f6"><style type="text/css">
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6;
|
||||
}
|
||||
body {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
@media only screen and (max-width: 640px) {
|
||||
h1 {
|
||||
font-weight: 600 !important; margin: 20px 0 5px !important;
|
||||
}
|
||||
h2 {
|
||||
font-weight: 600 !important; margin: 20px 0 5px !important;
|
||||
}
|
||||
h3 {
|
||||
font-weight: 600 !important; margin: 20px 0 5px !important;
|
||||
}
|
||||
h4 {
|
||||
font-weight: 600 !important; margin: 20px 0 5px !important;
|
||||
}
|
||||
h1 {
|
||||
font-size: 22px !important;
|
||||
}
|
||||
h2 {
|
||||
font-size: 18px !important;
|
||||
}
|
||||
h3 {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
.container {
|
||||
width: 100% !important;
|
||||
}
|
||||
.content {
|
||||
padding: 10px !important;
|
||||
}
|
||||
.content-wrapper {
|
||||
padding: 10px !important;
|
||||
}
|
||||
.invoice {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<table class="body-wrap" style="background: #f6f6f6; box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0; width: 100%" bgcolor="#f6f6f6">
|
||||
<tr style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<td align="center" width="100%" colspan="2" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0; vertical-align: top" valign="top"><img src="https://hostr.co/images/logo-dark-r.png" height="22" width="26" class="logo" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 40px 0 20px; max-width: 100%; padding: 0" /></td>
|
||||
</tr>
|
||||
<tr style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<td style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0; vertical-align: top" valign="top"></td>
|
||||
<td class="container" width="600" style="box-sizing: border-box; clear: both !important; display: block !important; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0 auto; max-width: 600px !important; padding: 0; vertical-align: top" valign="top">
|
||||
<div class="content" style="box-sizing: border-box; display: block; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0 auto; max-width: 600px; padding: 20px">
|
||||
<table class="main" width="100%" cellpadding="0" cellspacing="0" style="background: #fff; border-radius: 3px; border: 1px solid #e9e9e9; box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0" bgcolor="#fff">
|
||||
<tr style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<td class="content-wrap" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 20px; vertical-align: top" valign="top">
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<tr style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<td class="content-block" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0 0 20px; vertical-align: top" valign="top">
|
||||
Thanks for upgrading to Hostr Pro!
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<td class="content-block" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0 0 20px; vertical-align: top" valign="top">
|
||||
You've signed up for Hostr Pro Monthly at $6/month
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<td class="content-block" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0 0 20px; vertical-align: top" valign="top">
|
||||
— Jonathan Cremin, Hostr Founder
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="footer" style="box-sizing: border-box; clear: both; color: #999; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 20px; width: 100%">
|
||||
<table width="100%" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<tr style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<td class="aligncenter content-block" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 12px; margin: 0; padding: 0 0 20px; text-align: center; vertical-align: top" align="center" valign="top">Follow <a href="http://twitter.com/gethostr" style="box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 12px; margin: 0; padding: 0; text-decoration: underline">@gethostr</a> on Twitter.</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div></div>
|
||||
</td>
|
||||
<td style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0; vertical-align: top" valign="top"></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
56
api/views/email/pro.html
Normal file
56
api/views/email/pro.html
Normal file
|
@ -0,0 +1,56 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Hostr Pro</title>
|
||||
<link href="style.css" media="all" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<table class="body-wrap">
|
||||
<tr>
|
||||
<td align="center" width="100%" colspan="2"><img src="https://hostr.co/images/logo-dark-r.png" height="22" width="26" class="logo" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="container" width="600">
|
||||
<div class="content">
|
||||
<table class="main" width="100%" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td class="content-wrap">
|
||||
<table width="100%" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
Thanks for upgrading to Hostr Pro!
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
You've signed up for Hostr Pro Monthly at $6/month
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
— Jonathan Cremin, Hostr Founder
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="footer">
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td class="aligncenter content-block">Follow <a href="http://twitter.com/gethostr">@gethostr</a> on Twitter.</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div></div>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
271
api/views/email/style.css
Normal file
271
api/views/email/style.css
Normal file
|
@ -0,0 +1,271 @@
|
|||
/* -------------------------------------
|
||||
GLOBAL
|
||||
A very basic CSS reset
|
||||
------------------------------------- */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-text-size-adjust: none;
|
||||
width: 100% !important;
|
||||
height: 100%;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* Let's make sure all tables have defaults */
|
||||
table td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
BODY & CONTAINER
|
||||
------------------------------------- */
|
||||
body {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
.body-wrap {
|
||||
background-color: #f6f6f6;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: block !important;
|
||||
max-width: 600px !important;
|
||||
margin: 0 auto !important;
|
||||
/* makes it centered */
|
||||
clear: both !important;
|
||||
}
|
||||
|
||||
.content {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
HEADER, FOOTER, MAIN
|
||||
------------------------------------- */
|
||||
.main {
|
||||
background: #fff;
|
||||
border: 1px solid #e9e9e9;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.content-wrap {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.content-block {
|
||||
padding: 0 0 20px;
|
||||
}
|
||||
|
||||
.header {
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin-top: 40px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
width: 100%;
|
||||
clear: both;
|
||||
color: #999;
|
||||
padding: 20px;
|
||||
}
|
||||
.footer a {
|
||||
color: #999;
|
||||
}
|
||||
.footer p, .footer a, .footer unsubscribe, .footer td {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
TYPOGRAPHY
|
||||
------------------------------------- */
|
||||
h1, h2, h3 {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
|
||||
color: #000;
|
||||
margin: 40px 0 0;
|
||||
line-height: 1.2;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 32px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
p, ul, ol {
|
||||
margin-bottom: 10px;
|
||||
font-weight: normal;
|
||||
}
|
||||
p li, ul li, ol li {
|
||||
margin-left: 5px;
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
LINKS & BUTTONS
|
||||
------------------------------------- */
|
||||
a {
|
||||
color: #456470;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
text-decoration: none;
|
||||
color: #FFF;
|
||||
background-color: #456470;
|
||||
border: solid #456470;
|
||||
/* seems to be a bug stopping this from being applied above */
|
||||
border-color: #456470;
|
||||
border-width: 10px 20px;
|
||||
line-height: 2;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
border-radius: 5px;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
OTHER STYLES THAT MIGHT BE USEFUL
|
||||
------------------------------------- */
|
||||
.last {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.first {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.aligncenter {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.alignright {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.alignleft {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
ALERTS
|
||||
Change the class depending on warning email, good email or bad email
|
||||
------------------------------------- */
|
||||
.alert {
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
.alert a {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
}
|
||||
.alert.alert-warning {
|
||||
background: #ff9f00;
|
||||
}
|
||||
.alert.alert-bad {
|
||||
background: #d0021b;
|
||||
}
|
||||
.alert.alert-good {
|
||||
background: #68b90f;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
INVOICE
|
||||
Styles for the billing table
|
||||
------------------------------------- */
|
||||
.invoice {
|
||||
margin: 40px auto;
|
||||
text-align: left;
|
||||
width: 80%;
|
||||
}
|
||||
.invoice td {
|
||||
padding: 5px 0;
|
||||
}
|
||||
.invoice .invoice-items {
|
||||
width: 100%;
|
||||
}
|
||||
.invoice .invoice-items td {
|
||||
border-top: #eee 1px solid;
|
||||
}
|
||||
.invoice .invoice-items .total td {
|
||||
border-top: 2px solid #333;
|
||||
border-bottom: 2px solid #333;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* -------------------------------------
|
||||
RESPONSIVE AND MOBILE FRIENDLY STYLES
|
||||
------------------------------------- */
|
||||
@media only screen and (max-width: 640px) {
|
||||
h1, h2, h3, h4 {
|
||||
font-weight: 600 !important;
|
||||
margin: 20px 0 5px !important;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 22px !important;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 18px !important;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.content, .content-wrapper {
|
||||
padding: 10px !important;
|
||||
}
|
||||
|
||||
.invoice {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue