@@ -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; | height: 7px; | ||||
border-radius: 50%; | border-radius: 50%; | ||||
background-color: var(--grey); | background-color: var(--grey); | ||||
margin-right: 5px; | |||||
} | } | ||||
&.due { | |||||
&.warning { | |||||
color: var(--warning); | color: var(--warning); | ||||
&::before { | &::before { | ||||
@@ -73,7 +74,7 @@ | |||||
} | } | ||||
} | } | ||||
&.overDue { | |||||
&.danger { | |||||
color: var(--red); | color: var(--red); | ||||
&::before { | &::before { | ||||
@@ -81,7 +82,7 @@ | |||||
} | } | ||||
} | } | ||||
&.paid { | |||||
&.success { | |||||
color: var(--teal); | color: var(--teal); | ||||
&::before { | &::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 CogIcon } from 'ionicons/dist/svg/cog-outline.svg'; | ||||
import { ReactComponent as LineChartIcon } from 'ionicons/dist/svg/stats-chart.svg'; | import { ReactComponent as LineChartIcon } from 'ionicons/dist/svg/stats-chart.svg'; | ||||
import styles from './accounts.module.scss'; | 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 = [{ | const sampleInvoiceData = [{ | ||||
invoice: { | invoice: { | ||||
@@ -102,46 +103,39 @@ const Accounts: React.FC = () => { | |||||
</header> | </header> | ||||
{sampleInvoiceData.map((invoice, key) => { | {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> | ||||
</div> | </div> | ||||
</IonContent> | </IonContent> | ||||
</IonPage> | </IonPage> | ||||
); | ); | ||||