@@ -1,130 +0,0 @@ | |||
import React, { useState } from 'react'; | |||
import styles from './invoice.module.scss'; | |||
import { ReactComponent as ChevronBack } from 'ionicons/dist/svg/chevron-back.svg'; | |||
import { format } from 'date-fns'; | |||
import { IonButton, IonDatetime, IonInput } from '@ionic/react'; | |||
type OwnProps = { | |||
invoice: { | |||
id: string, | |||
date: string, | |||
status: string, | |||
dateOfPayment?: string, | |||
referenceNumber?: string, | |||
}, | |||
client: { | |||
name: string, | |||
logo: string, | |||
project: { | |||
name: string, | |||
contract: { | |||
name: string, | |||
amount: string, | |||
}, | |||
} | |||
} | |||
} | |||
export const InvoiceCard: React.FC<OwnProps> = (props) => { | |||
const [showDetails, setShowDetails] = useState<boolean>(false); | |||
const [formInputs, setFormInputs] = useState<{ | |||
dateOfPayment: string, | |||
referenceNumber: string, | |||
}>({ | |||
dateOfPayment: props.invoice.dateOfPayment ? props.invoice.dateOfPayment.toString() : '', | |||
referenceNumber: props.invoice.referenceNumber ? props.invoice.referenceNumber : '', | |||
}); | |||
let statusClass = ''; | |||
switch (props.invoice.status) { | |||
case 'due': statusClass = styles.due; break; | |||
case 'over due': statusClass = styles.overDue; break; | |||
case 'paid': statusClass = styles.paid; break; | |||
case 'cancelled': statusClass = styles.cancelled; break; | |||
default: break; | |||
} | |||
return <div> | |||
<section className={styles.card} onClick={() => setShowDetails(true)}> | |||
<figure> | |||
<img src={props.client.logo} alt="logo" /> | |||
</figure> | |||
<div className={styles.contentHolder}> | |||
<h6> Invoice ID: {props.invoice.id} </h6> | |||
<h2> {props.client.project.contract.amount} </h2> | |||
<p> {props.client.project.contract.name} </p> | |||
</div> | |||
<div className={styles.status}> | |||
<span className={statusClass}> {props.invoice.status} </span> | |||
</div> | |||
</section> | |||
{ showDetails && <div className={styles.backdrop}> | |||
<section className={styles.cardDetails}> | |||
<header> | |||
<IonButton onClick={() => setShowDetails(false)} fill={'clear'} size={'small'}> <ChevronBack /> </IonButton> | |||
<h4> Pending Invoice </h4> | |||
</header> | |||
<ul> | |||
<li> | |||
<label> Invoice ID </label> | |||
<p> {props.invoice.id} </p> | |||
</li> | |||
<li> | |||
<label> Invoice Date </label> | |||
<p> {format(new Date(props.invoice.date), 'dd MMMM yyyy')} </p> | |||
</li> | |||
<li> | |||
<label> Client </label> | |||
<p> {props.client.name} </p> | |||
</li> | |||
<li> | |||
<label> Project </label> | |||
<p> {props.client.project.name} </p> | |||
</li> | |||
<li> | |||
<label> Contract </label> | |||
<p> {props.client.project.contract.name} </p> | |||
</li> | |||
<li> | |||
<label> Invoice Amount </label> | |||
<p> {props.client.project.contract.amount} </p> | |||
</li> | |||
</ul> | |||
<section className={styles.form}> | |||
<div className={styles.inputHolder}> | |||
<label> Payment Date </label> | |||
<IonDatetime value={formInputs.dateOfPayment} mode={'ios'} placeholder={'DD/MM/YYYY'} displayFormat={'DD/MM/YYYY'} | |||
onIonChange={(e) => setFormInputs({ | |||
dateOfPayment: e.detail.value? e.detail.value.toString() : '', | |||
referenceNumber: formInputs.referenceNumber, | |||
})}></IonDatetime> | |||
</div> | |||
<div className={styles.inputHolder}> | |||
<label> Reference No. </label> | |||
<IonInput placeholder={'Enter here'} value={formInputs.referenceNumber} | |||
onIonChange={(e) => setFormInputs({ | |||
dateOfPayment: formInputs.dateOfPayment, | |||
referenceNumber: e.detail.value? e.detail.value.toString() : '', | |||
})}></IonInput> | |||
</div> | |||
{(props.invoice.status !== 'cancelled' && props.invoice.status !== 'paid' || formInputs.dateOfPayment !== props.invoice.dateOfPayment || formInputs.dateOfPayment !== props.invoice.date) && <div className={styles.buttonsHolder}> | |||
<IonButton fill={'outline'} className={styles.cancel} shape={'round'}> Cancel Invoice </IonButton> | |||
<IonButton fill={'solid'} className={styles.approve + ' ' + (formInputs.dateOfPayment && formInputs.referenceNumber ? '' : styles.disabled)} shape={'round'} | |||
onClick={() => setShowDetails(false)}> Paid </IonButton> | |||
</div>} | |||
</section> | |||
</section> | |||
</div> } | |||
</div> | |||
} |
@@ -63,9 +63,10 @@ | |||
height: 7px; | |||
border-radius: 50%; | |||
background-color: var(--grey); | |||
margin-right: 5px; | |||
} | |||
&.due { | |||
&.warning { | |||
color: var(--warning); | |||
&::before { | |||
@@ -73,7 +74,7 @@ | |||
} | |||
} | |||
&.overDue { | |||
&.danger { | |||
color: var(--red); | |||
&::before { | |||
@@ -81,7 +82,7 @@ | |||
} | |||
} | |||
&.paid { | |||
&.success { | |||
color: var(--teal); | |||
&::before { |
@@ -0,0 +1,102 @@ | |||
import React, { useState } from 'react'; | |||
import styles from './itemCard.module.scss'; | |||
import { ReactComponent as ChevronBack } from 'ionicons/dist/svg/chevron-back.svg'; | |||
import { IonButton } from '@ionic/react'; | |||
type OwnProps = { | |||
leftImage?: string, | |||
heading: { | |||
name: string, | |||
value: string | |||
}, | |||
value: string, | |||
description?: string, | |||
rightText?: { | |||
name: string, | |||
type: 'success' | 'danger' | 'warning' | undefined | |||
}, | |||
details?: Array<{ | |||
name: string, | |||
value: string | |||
}>, | |||
form?: JSX.Element | |||
} | |||
// Card - Image on the left, heading-value-description in the middle and status or any text on the right. eg: Pending invoice cards | |||
export const ItemCard: React.FC<OwnProps> = (props) => { | |||
const [showDetails, setShowDetails] = useState<boolean>(false); | |||
let statusClass = ''; | |||
if (props.rightText && props.rightText.type) { | |||
switch(props.rightText.type) { | |||
case 'success' : statusClass = styles.success; break; | |||
case 'danger' : statusClass = styles.danger; break; | |||
case 'warning' : statusClass = styles.warning; break; | |||
default: statusClass = ''; | |||
} | |||
} | |||
return <div> | |||
<section className={styles.card} onClick={() => setShowDetails(true)}> | |||
<figure> | |||
<img src={props.leftImage} /> | |||
</figure> | |||
<div className={styles.contentHolder}> | |||
<h6> { props.heading.name }: {props.heading.value} </h6> | |||
<h2> {props.value} </h2> | |||
<p> {props.description} </p> | |||
</div> | |||
{ props.rightText && <div className={styles.status}> | |||
<span | |||
className={statusClass}> { props.rightText.name } </span> | |||
</div> } | |||
</section> | |||
{ showDetails && props.details && <div className={styles.backdrop} onClick={(e: any) => { | |||
if (e.target.className.toString().includes('backdrop')) { | |||
setShowDetails(false); | |||
} | |||
}}> | |||
<section className={styles.cardDetails}> | |||
<header> | |||
<IonButton onClick={() => setShowDetails(false)} fill={'clear'} size={'small'}> <ChevronBack /> </IonButton> | |||
<h4> Pending Invoice </h4> | |||
</header> | |||
<ul> | |||
{ props.details.map((detail, key) => { | |||
return <li key={key}> | |||
<label> { detail.name } </label> | |||
<p> { detail.value } </p> | |||
</li> | |||
}) } | |||
</ul> | |||
{ props.form } | |||
</section> | |||
</div> } | |||
</div> | |||
} | |||
{/* <section className={styles.form}> | |||
<div className={styles.inputHolder}> | |||
<label> Payment Date </label> | |||
<IonDatetime mode={'ios'} placeholder={'DD/MM/YYYY'} displayFormat={'DD/MM/YYYY'}></IonDatetime> | |||
</div> | |||
<div className={styles.inputHolder}> | |||
<label> Reference No. </label> | |||
<IonInput placeholder={'Enter here'}></IonInput> | |||
</div> | |||
<div className={styles.buttonsHolder}> | |||
<IonButton fill={'outline'} className={styles.cancel} shape={'round'}> Cancel Invoice </IonButton> | |||
<IonButton fill={'solid'} className={styles.approve} shape={'round'} | |||
onClick={() => setShowDetails(false)}> Paid </IonButton> | |||
</div> | |||
</section> */} |
@@ -1,10 +0,0 @@ | |||
import React from 'react'; | |||
import styles from './invoice.module.scss'; | |||
import { format } from 'date-fns'; | |||
export const TransactionCard: React.FC = () => { | |||
return <div className={styles.card}> | |||
</div> | |||
} |
@@ -2,7 +2,8 @@ import { IonContent, IonPage } from '@ionic/react'; | |||
import { ReactComponent as CogIcon } from 'ionicons/dist/svg/cog-outline.svg'; | |||
import { ReactComponent as LineChartIcon } from 'ionicons/dist/svg/stats-chart.svg'; | |||
import styles from './accounts.module.scss'; | |||
import { InvoiceCard } from '../../components/invoice-card/invoice'; | |||
import { ItemCard } from '../../components/item-card/itemCard'; | |||
import { format } from 'date-fns'; | |||
const sampleInvoiceData = [{ | |||
invoice: { | |||
@@ -102,46 +103,39 @@ const Accounts: React.FC = () => { | |||
</header> | |||
{sampleInvoiceData.map((invoice, key) => { | |||
return <InvoiceCard key={key} invoice={invoice.invoice} client={invoice.client} /> | |||
})} | |||
</div> | |||
<div className={styles.dashboardContainerSegment}> | |||
<header> | |||
<h5> Pending Invoices </h5> | |||
<a> See All </a> | |||
</header> | |||
{sampleInvoiceData.map((invoice, key) => { | |||
return <InvoiceCard key={key} invoice={invoice.invoice} client={invoice.client} /> | |||
})} | |||
</div> | |||
<div className={styles.dashboardContainerSegment}> | |||
<header> | |||
<h5> Pending Invoices </h5> | |||
<a> See All </a> | |||
</header> | |||
{sampleInvoiceData.map((invoice, key) => { | |||
return <InvoiceCard key={key} invoice={invoice.invoice} client={invoice.client} /> | |||
})} | |||
</div> | |||
<div className={styles.dashboardContainerSegment}> | |||
<header> | |||
<h5> Pending Invoices </h5> | |||
<a> See All </a> | |||
</header> | |||
{sampleInvoiceData.map((invoice, key) => { | |||
return <InvoiceCard key={key} invoice={invoice.invoice} client={invoice.client} /> | |||
return <ItemCard key={key} | |||
leftImage={invoice.client.logo} | |||
heading={{ name: 'Invoice ID', value: invoice.invoice.id }} | |||
value={invoice.client.project.contract.amount} | |||
description={invoice.client.project.contract.name} | |||
rightText={{ | |||
name: invoice.invoice.status, | |||
type: invoice.invoice.status === 'due' ? 'warning' : 'danger' | |||
}} | |||
details={[{ | |||
name: 'Invoice ID', | |||
value: invoice.invoice.id, | |||
}, { | |||
name: 'Invoice Date', | |||
value: format(new Date(invoice.invoice.date), 'dd MMMM yyyy') | |||
}, { | |||
name: 'Client', | |||
value: invoice.client.name | |||
}, { | |||
name: 'Project', | |||
value: invoice.client.project.name | |||
}, { | |||
name: 'Contract', | |||
value: invoice.client.project.contract.name | |||
}, { | |||
name: 'Invoice Amount', | |||
value: invoice.client.project.contract.amount | |||
}]} | |||
/> | |||
})} | |||
</div> | |||
</div> | |||
</IonContent> | |||
</IonPage> | |||
); | |||