Skip to content

Commit

Permalink
updated refund method, added alerts
Browse files Browse the repository at this point in the history
  • Loading branch information
psilly-rabbit committed Aug 30, 2023
1 parent c52f7d0 commit b77fc1b
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 73 deletions.
6 changes: 3 additions & 3 deletions backend/src/handlers/payments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export default function mountPaymentsEndpoints(router: Router) {

/*
*
* USER TO APP PAYMENT FUNCTIONS

This comment has been minimized.

Copy link
@Andestra

Andestra Jan 7, 2025

ES8915632626313261614466

* USER TO APP PAYMENT
*
*/

Expand Down Expand Up @@ -140,7 +140,7 @@ export default function mountPaymentsEndpoints(router: Router) {

/*
*
* APP TO USER PAYMENT FUNCTIONS
* APP TO USER PAYMENT
*
*/

Expand Down Expand Up @@ -246,7 +246,7 @@ export default function mountPaymentsEndpoints(router: Router) {
await pi.completePayment(paymentId, refundTxId);

// return success to the front end
return res.status(200).json({message: `${refundedPaymentID} was refunded with transaction ${refundTxId}`, block_explorer_link: `https://blockexplorer.minepi.com/tx/${refundTxId}`});

This comment has been minimized.

Copy link
@Andestra

Andestra Jan 7, 2025

ES8915632626313261614466

return res.status(200).json({message: `Payment: ${refundedPaymentID} was refunded with transaction ${refundTxId}`, block_explorer_link: `https://blockexplorer.minepi.com/tx/${refundTxId}`});
} catch (error) {
console.log(error)
}
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/Shop/components/Auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const axiosClient = axios.create({ baseURL: `${backendURL}`, timeout: 20000, wit

const AuthProvider: React.FC<React.ReactNode> = ({ children }) => {
const [user, setUser] = React.useState<User>( { uid: '', username: '' } )
const [showModal, setShowModal] = React.useState<boolean>(true);
const [showModal, setShowModal] = React.useState<boolean>(false);
const [refunds, setRefunds] = React.useState<RefundType[]>(
[{
_id: '',
Expand All @@ -43,6 +43,7 @@ const AuthProvider: React.FC<React.ReactNode> = ({ children }) => {
const authResult: AuthResult = await window.Pi.authenticate(scopes, onIncompletePaymentFound);
await signInUser(authResult);
setUser(authResult.user);
setShowModal(false);
saveRefunds();
}

Expand Down Expand Up @@ -74,15 +75,14 @@ const AuthProvider: React.FC<React.ReactNode> = ({ children }) => {
saveShowModal(false);
}


const userContext: UserContextType = {
user,
saveUser,
showModal,
saveShowModal,
refunds,
saveRefunds,
onModalClose
onModalClose,
}

return (

This comment has been minimized.

Copy link
@Andestra

Andestra Jan 7, 2025

ES8915632626313261614466

Expand Down
7 changes: 7 additions & 0 deletions frontend/src/Shop/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export default function ColorInversionFooter() {
const [ color ] = React.useState<ColorPaletteProp>('neutral');

return (
<Grid
container
position={'sticky'}
bottom={0}
>
<Sheet
variant="soft"
color={color}
Expand All @@ -28,6 +33,7 @@ export default function ColorInversionFooter() {
p: 2,
borderRadius: { xs: 0, sm: 'sm' },
}}

>
<Grid container justifyContent='center'>
<Typography alignContent="center">
Expand Down Expand Up @@ -121,5 +127,6 @@ export default function ColorInversionFooter() {
</List>
</Box>
</Sheet>
</Grid>
);
}
46 changes: 23 additions & 23 deletions frontend/src/Shop/components/Refund.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
import React, { CSSProperties } from 'react';
import { Dialog, DialogContent, DialogContentText, DialogActions, Button } from '@mui/material';
import { Link } from 'react-router-dom';

/*
* this card displays the alert message that a refund has been processed
*/

interface Props {
refundedTransactionMessage: string,
refundedTransaction: {
message: string,
block_explorer_link: string
},
showRefundAlert: boolean,
onRefundClose: () => void,
}

const modalStyle: CSSProperties = {
background: 'white',
position: 'absolute',
left: '15vw',
top: '40%',
width: '70vw',
height: '25vh',
border: '1px solid black',
textAlign: 'center',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center'
}

export default function Refund(props: Props) {
return (
<div style={modalStyle}>
<p style={{ fontWeight: 'bold' }}>Refunded Payment</p>
<div>
<p>{props.refundedTransactionMessage}</p>
<button onClick={props.onRefundClose}>Close</button>
</div>
</div>
<Dialog
open={props.showRefundAlert}
onClose={props.onRefundClose}
>
<DialogContent>
<DialogContentText marginTop={1}>
{props.refundedTransaction.message}
</DialogContentText>
<DialogContentText marginTop={2}>
<a href={props.refundedTransaction.block_explorer_link}>View on the Pi Block Explorer</a>
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={props.onRefundClose}>Close</Button>
</DialogActions>
</Dialog>
)
}
27 changes: 23 additions & 4 deletions frontend/src/Shop/components/RefundCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,30 @@ interface Props {
pictureCaption: string,
pictureURL: string,
amount: number,
variant: boolean,
onClickRefund: () => void,
}

export default function RefundCard(props: Props) {

function buttonStyle(){
if(props.variant){
return 'outlined';
}
else{
return 'contained';
}
}

function buttonText(){
if(props.variant){
return 'Refund in Progress';
}
else{
return 'Refund';
}
}

return (
<Grid>
{ (props.name === 'none')?
Expand All @@ -37,12 +57,11 @@ export default function RefundCard(props: Props) {
:
<Grid container style={{ margin: 16, paddingBottom: 16, borderBottom: '1px solid gray' }}>
<Grid container style={{ display: 'flex', flexDirection: 'row' }}>
<Grid item style={{ width: "33%", marginRight: 8 }}>
<Grid container style={{ width: "33%", marginRight: 8 }}>
<AspectRatio sx={{ width: 300 }}>
<img style={{ width: "100%" }} src={props.pictureURL} alt={props.name} />
<img style={{ width: "100%", height: "100%" }} src={props.pictureURL} alt={props.name} />
</AspectRatio>
</Grid>

<Grid item style={{ width: "66%" }}>
{props.name ==="lemon_pie_1" ? <h3>Refund Order: Lemon Meringue Pie</h3> : <h3>Refund Order: Apple Pie</h3> }
<p>{props.description}</p>
Expand All @@ -53,7 +72,7 @@ export default function RefundCard(props: Props) {
<Grid container>
<Grid item style={{textAlign: 'center', margin: 8}}>
<strong>Eligible Refund: {props.amount} Test-π</strong> <br />
<Button variant='contained' color='secondary' onClick={() => {props.onClickRefund()}}>Refund</Button>
<Button variant={buttonStyle()} color='secondary' onClick={() => {props.onClickRefund()}}>{buttonText()}</Button>
</Grid>
<Grid item>
<span style={{fontSize: '0.6em'}}>{props.pictureCaption}</span>
Expand Down
38 changes: 16 additions & 22 deletions frontend/src/Shop/components/SignIn.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { CSSProperties } from 'react';
import { Dialog, DialogContent, DialogContentText, DialogActions, Button } from '@mui/material';

/*
* this card displays the Sign-In alert when a user is not signed in
Expand All @@ -7,30 +7,24 @@ import React, { CSSProperties } from 'react';
interface Props {
onSignIn: () => void,
onModalClose: () => void,
}

const modalStyle: CSSProperties = {
background: 'white',
position: 'absolute',
left: '15vw',
top: '40%',
width: '70vw',
height: '25vh',
border: '1px solid black',
textAlign: 'center',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center'
showModal: boolean,
}

export default function SignIn(props: Props) {
return (
<div style={modalStyle}>
<p style={{ fontWeight: 'bold' }}>You need to sign in first.</p>
<div>
<button onClick={props.onSignIn} style={{ marginRight: '1em' }}>Sign in</button>
<button onClick={props.onModalClose}>Close</button>
</div>
</div>
<Dialog
open={props.showModal}
onClose={props.onModalClose}
>
<DialogContent>
<DialogContentText>
You need to sign in first.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={props.onSignIn}>Sign In</Button>
<Button onClick={props.onModalClose}>Close</Button>
</DialogActions>
</Dialog>
)
}
33 changes: 23 additions & 10 deletions frontend/src/Shop/pages/AppToUser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Refund from "../components/Refund";

const _window: WindowWithEnv = window;
const backendURL = _window.__ENV && _window.__ENV.backendURL;
const axiosClient = axios.create({ baseURL: `${backendURL}`, timeout: 20000, withCredentials: true});
const axiosClient = axios.create({ baseURL: `${backendURL}`, timeout: 35000, withCredentials: true});

This comment has been minimized.

Copy link
@Andestra

Andestra Jan 7, 2025

ES8915632626313261614466


/*
* this page retrieves and displays all the eligible refunds a user has.
Expand All @@ -22,41 +22,52 @@ export default function AppToUserPayments() {
const { user, saveUser, saveShowModal, showModal, refunds, saveRefunds, onModalClose } = React.useContext(UserContext) as UserContextType;
const [showRefundAlert, setShowRefundAlert] = useState(false);
const [refundInfoState, setRefundInformation] = useState<{message: string, block_explorer_link: string}>({message: "", block_explorer_link: ""});
const [refundProcessing, setRefundProcessing] = useState(false);

const orderRefund = async (memo: string, originalPayment: RefundType) => {
if(user === null) {
if(refundProcessing){
return console.log("refund already in progress");
}

setRefundProcessing(true);
if(user.uid === "") {
setRefundProcessing(false);
return saveShowModal(true);
}

const refundPaymentID = originalPayment.pi_payment_id;

This comment has been minimized.

Copy link
@Andestra

Andestra Jan 7, 2025

import React from "react";
import { User, AuthResult, UserContextType, WindowWithEnv, RefundType } from "./Types";
import axios from "axios";
import { onIncompletePaymentFound } from "./Payments";

/*
The useContext Hook is iniated here to pass the user information
between the various pages of the app. It is important to use the
react-dom links in your app so there is no re-render which causes
loss of the context.

To read more on react context see, https://react.dev/reference/react/useContext
*/

export const UserContext = React.createContext<UserContextType | null >(null);

const _window: WindowWithEnv = window;
const backendURL = _window.__ENV && _window.__ENV.backendURL;

const axiosClient = axios.create({ baseURL: ${backendURL}, timeout: 20000, withCredentials: true});

const AuthProvider: React.FC<React.ReactNode> = ({ children }) => {
const [user, setUser] = React.useState( { uid: '', username: '' } )
const [showModal, setShowModal] = React.useState(true);
const [showModal, setShowModal] = React.useState(false);
const [refunds, setRefunds] = React.useState<RefundType[]>(
[{
_id: '',
pi_payment_id: '',
product_id: '',
user: '',
amount: 0,
txid: '',
paid: false,
cancelled: false,
completed: false,
created_at: '',
is_refund: false,
refunded_at: ''
}]);

const signIn = async () => {
const scopes = ['username', 'payments', 'wallet_address'];
const authResult: AuthResult = await window.Pi.authenticate(scopes, onIncompletePaymentFound);
await signInUser(authResult);
setUser(authResult.user);
setShowModal(false);
saveRefunds();
}

const signInUser = async (authResult: AuthResult) => {
await axiosClient.post('/user/signin', {authResult});
return setShowModal(false);
}

const signOutUser = async() =>{
const nullUser = { uid: '', username: '' };
setUser(nullUser);
}

const saveUser = () =>{
user.uid === '' ? signIn() : signOutUser();
}

const saveShowModal = (value: boolean) => {
setShowModal(value);
}

const saveRefunds = async() =>{
const refundableOrders = await axiosClient.post('/payments/refundable_payment');
const refundable: RefundType[] = refundableOrders.data.refundableOrders;
setRefunds(refundable)
}

const onModalClose = () => {
saveShowModal(false);
}

const userContext: UserContextType = {
user,
saveUser,
showModal,
saveShowModal,
refunds,
saveRefunds,
onModalClose
onModalClose,
}

return (
<UserContext.Provider value={ userContext }>
{children}
</UserContext.Provider>
)

}

export default AuthProvider;

const refundPaymentAmount = originalPayment.amount;
const paymentData = { memo, refundPaymentID, refundPaymentAmount};
const refundInformation: typeof refundInfoState = await axiosClient.post('/payments/refundable_payment/refund_payment', paymentData);

const returnInfo = await axiosClient.post('/payments/refundable_payment/refund_payment', paymentData);
const refundInformation = returnInfo.data
console.log('refund information: ', refundInformation)
setRefundInformation(refundInformation);
setShowRefundAlert(true);

saveRefunds();
setShowRefundAlert(true);
setRefundProcessing(false);
}

useEffect(() => {
saveRefunds();
}, []);
},[]);

return (
<>
<Header/>
<Typography variant="h4" margin={3}>
App to User Payments
</Typography>
{
refunds[0] === undefined || refunds[0]._id === '' ?
{(user.uid === '' || refunds[0] === undefined) ?
<RefundCard
name= 'none'
description= "Did the delivery person eat your pie and now you need a refund?"
pictureCaption="Picture by David McLeish - https://www.flickr.com/photos/shishberg/2310078068/, CC BY-SA 2.0"
pictureURL="https://live.staticflickr.com/2143/2310078068_627e69cea2_k.jpg"
amount={1}
onClickRefund={()=> saveRefunds()}
variant={refundProcessing}
/>
:
refunds.map((order: RefundType) =>{
Expand All @@ -68,12 +79,14 @@ return (
pictureURL="https://live.staticflickr.com/2143/2310078068_627e69cea2_k.jpg"
amount={order.amount}
onClickRefund={()=> orderRefund("User Requested Refund", order)}
variant={refundProcessing}
/>
})
}

{ showModal && <SignIn onSignIn={saveUser} onModalClose={onModalClose} showModal={showModal}/> }
{ showRefundAlert && <Refund refundedTransaction={refundInfoState} onRefundClose={() => setShowRefundAlert(false)} showRefundAlert={showRefundAlert} /> }

{ showModal && <SignIn onSignIn={saveUser} onModalClose={onModalClose} /> }
{ showRefundAlert && <Refund refundedTransactionMessage={refundInfoState.message} onRefundClose={() => setShowRefundAlert(false)} /> }
<Footer/>
</>
)
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/Shop/pages/UserToApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function UserToAppPayments() {
const { user, saveUser, showModal, saveShowModal, onModalClose } = React.useContext(UserContext) as UserContextType;

const orderProduct = async (memo: string, amount: number, paymentMetadata: MyPaymentMetadata) => {
if(user === null) {
if(user.uid === "") {
return saveShowModal(true);
}

Expand All @@ -40,7 +40,6 @@ return(
<Typography variant="h4" margin={3}>
User to App Payments
</Typography>

<ProductCard
name="Apple Pie"
description="You know what this is. Pie. Apples. Apple pie."
Expand All @@ -59,7 +58,8 @@ return(
onClickBuy={() => orderProduct("Order Lemon Meringue Pie", 5, { productId: 'lemon_pie_1' })}
/>

{ showModal && <SignIn onSignIn={saveUser} onModalClose={onModalClose} /> }
{ showModal && <SignIn onSignIn={saveUser} onModalClose={onModalClose} showModal={showModal}/> }

<Footer/>
</>
);
Expand Down
Loading

0 comments on commit b77fc1b

Please sign in to comment.