Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 2.0.2


- Remove node.js Example
- update the returned payment model desc
- payment view return bool instead of model

## 2.0.1

- Remove Get Payment Method
Expand Down
210 changes: 172 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,70 +60,55 @@ curl -X POST https://api.moosyl.com/payment-request \
}'
```

#### Node.js Example:

```javascript
const axios = require("axios");

async function createPaymentRequest() {
try {
const response = await axios.post(
"https://api.moosyl.com/payment-request",
{
phoneNumber: "+22212345678", // Optional
transactionId: "your-unique-transaction-id",
amount: 5000, // Amount in MRU
},
{
headers: {
Authorization: "YOUR_SECRET_API_KEY",
"Content-Type": "application/json",
},
}
);

console.log("Payment Request Created:", response.data);
} catch (error) {
console.error("Error creating payment request:", error.response.data);
}
}

createPaymentRequest();
```

---

### Step 2: Display the Payment View
### Step 2: Register Localization

Before displaying the payment UI, make sure your `MaterialApp` registers the Moosyl localization delegates and supported locales:

```dart
return MaterialApp(
localizationsDelegates: MoosylLocalization.localizationsDelegates,
supportedLocales: MoosylLocalization.supportedLocales,
locale: const Locale('en'), // Optional: use the device locale by default.
home: const PaymentScreen(),
);
```

Use `MoosylFlutter.show()` to open the payment flow. It returns `PaymentSuccess?` — non-null on success, `null` when the user closes without paying:
---

### Step 3: Open the Full Payment View

Use `MoosylFlutter.show()` when you want Moosyl to own the checkout payment UI. It returns `bool?`: a non-null value when the payment flow finishes, or `null` when the user closes the view without completing payment.

Set `isFullPage` to `true` for a pushed route or `false` for a bottom sheet.

```dart
import 'package:flutter/material.dart';
import 'package:moosyl_flutter/moosyl.dart';

class PaymentScreen extends StatelessWidget {
const PaymentScreen({super.key});

@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () async {
final payment = await MoosylFlutter.show(
final isSuccess = await MoosylFlutter.show(
context,
publishableApiKey: 'YOUR_PUBLISHABLE_API_KEY',
transactionId: 'TRANSACTION_ID', // From your backend
isFullPage: true, // false for bottom sheet
isFullPage: true, // false for bottom sheet
items: const [
MoosylPaymentSummaryItem(amount: 5000, label: 'amountToPay'),
MoosylPaymentSummaryItem(amount: 0, label: 'tax'),
],
isMasriviInBottomSheet: false,
masriviPhoneNumber: '+22212345678',
);
if (payment != null) {
print('Payment successful! id=${payment.id} amount=${payment.amount}');

if (isSuccess != null) {
print('Payment finished. isSuccess=$isSuccess');
}
},
child: const Text('Pay'),
Expand All @@ -132,7 +117,156 @@ class PaymentScreen extends StatelessWidget {
}
```

**Parameters:** `publishableApiKey`, `transactionId`, `isFullPage` (true = full page, false = bottom sheet), `amountToPay`, `tax`.
#### `MoosylFlutter.show()` Options

| Option | Type | Required | Description |
| --- | --- | --- | --- |
| `publishableApiKey` | `String` | Yes | Your Moosyl publishable API key. |
| `transactionId` | `String` | Yes | The transaction ID returned by your backend payment request. |
| `items` | `List<MoosylPaymentSummaryItem>?` | No | Summary rows shown in the payment view. When supplied, their total is validated against the payment request amount. Known localized labels include `amountToPay`, `tax`, `total`, and `totalAmount`; custom labels are shown as provided. |
| `isFullPage` | `bool` | No | Defaults to `true`. Use `false` to show the flow in a bottom sheet. |
| `isMasriviInBottomSheet` | `bool` | No | Controls whether Masrivi opens as bottom-sheet content inside the payment flow. |
| `masriviPhoneNumber` | `String?` | No | Optional phone number used to prefill the Masrivi payment page. |

---

## Embedded Payment Methods

Use `MoosylPaymentMethods` when your app owns the checkout screen and you only want Moosyl to load, display, select, and continue with payment methods.

```dart
class EmbeddedPaymentScreen extends StatefulWidget {
const EmbeddedPaymentScreen({super.key});

@override
State<EmbeddedPaymentScreen> createState() => _EmbeddedPaymentScreenState();
}

class _EmbeddedPaymentScreenState extends State<EmbeddedPaymentScreen> {
final _controller = MoosylPaymentMethodsController();
ConfigurationListDataInner? _selectedMethod;
bool _continueLoading = false;

@override
void dispose() {
_controller.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
final selectedTitle = _selectedMethod == null
? 'platform'
: PaymentMethodTypes.fromString(_selectedMethod!.type).title(context);

return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
MoosylPaymentMethods(
controller: _controller,
publishableApiKey: 'YOUR_PUBLISHABLE_API_KEY',
transactionId: 'TRANSACTION_ID',
selectedMethodId: _selectedMethod?.id,
onSelectMethod: (method) {
setState(() => _selectedMethod = method);
},
onContinueLoadingChange: (loading) {
setState(() => _continueLoading = loading);
},
onPaymentSuccess: (isSuccess) async {
print('Payment finished. isSuccess=$isSuccess');
},
primaryColor: const Color(0xFFF55E1E),
),
const SizedBox(height: 20),
FilledButton(
onPressed: _selectedMethod == null || _continueLoading
? null
: _controller.continuePayment,
child: Text(
_continueLoading ? 'Loading...' : 'Continue with $selectedTitle',
),
),
],
);
}
}
```

---

## Custom Payment Method UI

Pass `renderMethod` to draw each payment method row with your own widgets. Call `props.onSelect()` from your custom row so Moosyl can track the selected method.

```dart
MoosylPaymentMethods(
controller: _controller,
publishableApiKey: 'YOUR_PUBLISHABLE_API_KEY',
transactionId: 'TRANSACTION_ID',
selectedMethodId: selectedMethod?.id,
onSelectMethod: (method) {
setState(() => selectedMethod = method);
},
onContinueLoadingChange: (loading) {
setState(() => continueLoading = loading);
},
onPaymentSuccess: (isSuccess) async {
print('Payment finished. isSuccess=$isSuccess');
},
primaryColor: const Color(0xFFF55E1E),
renderMethod: (context, props) {
return ListTile(
onTap: props.onSelect,
leading: props.type.icon.apply(size: 36),
title: Text(props.title),
subtitle: Text(props.method.type),
trailing: props.isSelected ? const Icon(Icons.check_circle) : null,
);
},
)
```

`MoosylPaymentMethodRenderProps` gives your row everything it needs:

| Property | Description |
| --- | --- |
| `method` | Raw `ConfigurationListDataInner` payment method data from Moosyl. |
| `type` | Parsed `PaymentMethodTypes` value. |
| `title` | Localized payment method title. |
| `isSelected` | Whether this row is currently selected. |
| `selectedMethodId` | Currently selected method ID, if any. |
| `isRTL` | Whether the surrounding layout direction is RTL. |
| `onSelect` | Callback your custom UI should call when the row is selected. |

---

## `MoosylPaymentMethods` Options

| Option | Type | Description |
| --- | --- | --- |
| `publishableApiKey` | `String` | Required. Your Moosyl publishable API key. |
| `transactionId` | `String?` | Transaction ID used by `controller.continuePayment()`. |
| `amountToPay` | `double` | Amount used for validation when continuing. Defaults to `0.0`. |
| `tax` | `double` | Tax amount used with `amountToPay` when `totalAmount` is not supplied. Defaults to `0.0`. |
| `totalAmount` | `double?` | Total expected amount. Defaults to `amountToPay + tax`. |
| `selectedMethodId` | `String?` | Controlled selected method ID. |
| `onSelectMethod` | `ValueChanged<ConfigurationListDataInner>?` | Called whenever a method is selected. |
| `onPaymentSuccess` | `FutureOr<void> Function(bool)?` | Called when payment succeeds or reports a final success status. |
| `onPaymentError` | `ValueChanged<Object>?` | Called when loading or continuing payment fails. |
| `onContinueLoadingChange` | `ValueChanged<bool>?` | Called when `continuePayment()` starts and finishes. |
| `controller` | `MoosylPaymentMethodsController?` | Lets your screen call `continuePayment()` and read `selectedMethod`. Dispose it from your state object. |
| `primaryColor` | `Color?` | Accent color for default rows and dialogs. Defaults to the theme primary color. |
| `renderMethod` | `MoosylPaymentMethodBuilder?` | Custom builder for each payment method row. |
| `loadingComponent` | `Widget?` | Custom widget shown while payment methods are loading. |
| `loadingBuilder` | `MoosylPaymentMethodsLoadingBuilder?` | Builder for custom loading content with locale, color, and RTL props. |
| `showDefaultTitle` | `bool` | Whether the default UI includes its section title. Defaults to `true`. |
| `isMasriviInBottomSheet` | `bool` | Whether Masrivi opens in a bottom sheet from custom platform UIs. Defaults to `true`. |
| `masriviPresentation` | `MasriviWebViewPresentation` | Presentation used when `isMasriviInBottomSheet` is `false`. Defaults to `MasriviWebViewPresentation.fullPage`. |
| `masriviPhoneNumber` | `String?` | Optional phone number used to prefill Masrivi. |
| `masriviBottomSheetHeight` | `double` | Height factor for Masrivi bottom-sheet content. Defaults to `0.88`. |

For a complete working demo with the full payment view, embedded platforms, and custom payment method rows, see [`example/lib/main.dart`](example/lib/main.dart).

For detailed API documentation, visit the [Moosyl Flutter API Documentation](https://pub.dev/documentation/moosyl_flutter/latest/moosyl_flutter/moosyl_flutter-library.html).

Expand Down
Binary file modified assets/icons/amanty.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/icons/bankily.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/icons/bci_pay.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/icons/bim_bank.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/icons/masrivi.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/icons/sedad.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading