Payment through razorpay on flutter web produces error - flutter

I had implemented the razorpay payment gateway in my flutter project of an ecom store.
The payment works fine on mobile platform, but on web it is creating an issue. On web the user is redirected to different file named webpayment for making payment.
On web, when the user pays for an item on list page, the first time the webpayment gets succeeded and the user is redirected to detail page and on detail page when back button is pressed the user gets redirected to list page where other items are listed.
But when user pays for another item on list page the details of previous item whose payment was made is sent to webpayment page not the item on which the user had clicked.
Hot reloading the web,solves the problem but, now if after making another payment ,if user try to purchase another item the details of previous item is sent to the web payment page.Means user need to reload the page in web for making payment to another product.
The mobile app is working fine.There is some state management issue,I think in webpayment page which forces the details of previous purchased item to persist.
Below is the webpayment code which redirects user from list page to web payment page:
class Webpayment extends StatefulWidget {
final String? name;
final Map? buyer;
final String? postId;
final String? userId;
final String? category;
final String? usercity;
final double? price;
Webpayment({
Key? key,
this.name,
this.buyer,
this.postId,
this.userId,
this.category,
this.usercity,
this.price,
}) : super(key: key);
#override
_WebpaymentState createState() => _WebpaymentState(this.name, this.buyer,
this.postId, this.userId, this.category, this.usercity, this.price);
}
class _WebpaymentState extends State<Webpayment>
with AutomaticKeepAliveClientMixin<Webpayment> {
final String? name;
final Map? buyer;
final String? postId;
final String? userId;
final String? category;
final String? usercity;
final double? price;
_WebpaymentState(this.name, this.buyer, this.postId, this.userId,
this.category, this.usercity, this.price);
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
super.build(context);
ui.platformViewRegistry.registerViewFactory("rzp-html", (int viewId) {
IFrameElement element = IFrameElement();
window.onMessage.forEach((element) {
print('Event Received in callback: ${element.data}');
if (element.data == 'MODAL_CLOSED') {
} else if (element.data == 'SUCCESS') {
print('PAYMENT SUCCESSFULL!!!!!!! ${widget.postId}');
var userid = auth.currentUser!.uid.toString();
FirebaseFirestore.instance
.collection('${widget.category}${widget.usercity}')
.doc(widget.postId)
.update({'buyer.$userid': "true", 'deal': "Completed"});
Navigator.push(
this.context,
MaterialPageRoute(
builder: (context) => CategoryFeedDetail(
postId: widget.postId,
userId: widget.userId,
category: widget.category,
usercity: widget.usercity,
),
));
}
});
element.src =
'assets/payments.html?name=${widget.name}&price=${widget.price}';
element.style.border = 'none';
return element;
});
return Scaffold(body: Builder(builder: (BuildContext context) {
return Container(
child: HtmlElementView(viewType: 'rzp-html'),
);
}));
}
#override
void dispose() {
// TODO: implement dispose
super.dispose();
}
#override
bool get wantKeepAlive => false;
}
After payment the user is redirected to detail page and on detail page follwing is the code is there on back press to go on list page
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => CategoryFeed(
widget.userId, widget.usercity, widget.category),
),
);
}),

Related

How to link up web api call to the list view

So i have my dart call to my api get method. Btw the way am just learning flutter and dart and trying out basic crud operations I would use to be doing in .net and c#
import 'dart:convert';
import 'package:theapp/models/Players.dart';
import 'package:http/http.dart';
class ApiService {
final String apiUrl = "https://apiurlhidden.com/api";
final String getAllPlayersEndPoint = "/GetAllPlayers/";
Future<List<Player>> getAllPlayers() async {
final getallPlayersUrl = Uri.parse(apiUrl + getAllPlayersEndPoint);
Response res = await get(getallPlayersUrl);
if (res.statusCode == 200) {
List<dynamic> body = jsonDecode(res.body);
List<Player> players =
body.map((dynamic item) => Player.fromJson(item)).toList();
return players;
} else {
throw "Failed to load cases list";
}
}
}
And I have my listview here but it complaining saying key and players do not exist
import 'package:flutter/material.dart';
import 'package:theapp/models/Players.dart';
class PlayerList extends StatelessWidget {
List<Player> players = [];
PlayerList({Key key, this.players}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: players == null ? 0 : players.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: InkWell(
onTap: () {},
child: ListTile(
leading: Icon(Icons.person),
title: Text(players[index].firstName),
subtitle: Text(players[index].surname.toString()),
),
));
});
}
}
My Model
class Player {
final int id;
final int type;
final String playerLevel;
final String firstName;
final String surname;
Player(this.id, this.type, this.playerLevel, this.firstName, this.surname);
factory Player.fromJson(Map<String, dynamic> json) {
return Player(
json['id'],
json['type'],
json['playerlevel'],
json['firstname'],
json['surname'],
);
}
#override
String toString() =>
'Players{id: $id, firstName: $firstName, lastName: $surname}';
}
Is there any reason why it should not recognize players and key in my list view page also how do I get the items to appear in the listview.
Picture only added to show the context in the items I mentioned above. Also coming from a .net background I would normally use an observable collection so it gets any changes in data in real-time am I using the correct approach for that.
Use required keyword to make parameters mandatory.
PlayerList({required Key key, required this.players}) : super(key: key);
Named parameters are optional unless they’re explicitly marked as required.
See Parameters for details.

on login page navigation am sending the response

Am trying to achieve app that if person logged in the response of app is sent to another screen. here it is asking to add the same details in splash screen, am using shared preferences to see the user is logged in or not. how can we fix this issue.
splash.dart
#override
void initState() {
super.initState();
// navigate();
getValidationData().whenComplete(() async {
Future.delayed(const Duration(seconds: 6), () {
PageNavigator(ctx: context).nextPageOnly(
page: finalEmail == null ? const LoginPage() : const HomeScreen(// what to do here));
});
});
}
login.dart
///Save users data and then navigate to homepage
final int userId = res['userId'];
final String token = res['token'];
final bool recharge = res['recharge'];
final String name = res['name'];
PageNavigator(ctx: context).nextPageOnly(
page: HomeScreen(
userId: userId,
token: token,
recharge: recharge,
name: name,
));
home.dart
class HomeScreen extends StatefulWidget {
final int userId;
final String token;
final bool recharge;
final String name;
const HomeScreen({
Key? key,
required this.userId,
required this.token,
required this.recharge,
required this.name,
}) : super(key: key);

Provider automatically gets updated when calling setState

I am new to Flutter and currently working with Providers. I am pulling some static array list from an api and saving it to the Provider. I am letting the user to select from this list and attach to the Item he is creating using the form.
So, Everytime the user tries to create a new Item, he/she should see the static list with the selection set to false.
But, the provider array variable gets automatically updated upon calling setState. Below is the Issue I'm facing..
main.dart
MultiProvider(
providers: [
ChangeNotifierProvider<Info1Class>(
create: (ctx) => Info1Class(),
),
ChangeNotifierProvider<Info2Class>(
create: (ctx) => Info1Class(),
),
],
child: MaterialApp(
And in my Stateful widget in the build method. I am getting the Provider Details like this.
screenArray.clear();
final t = Provider.of<Info1Class>(context, listen: false).dataArray;
screenArray.addAll(t);
Whenever I call setState to update the elements of screenArray, the provider data gets updated as well.
setState(() {screenArray[0].selected = true})
After setState(), if I print the Provider dataArray's first element, it showing as true.
print(Provider.of<Info1Class>(context, listen: false).dataArray[0].selected)
My Dependancies
provider: ^4.3.2+4
Is there a way to avoid the Provider data getting updated and only update the variable in my Stateful Widget ?
Please let me know if I am missing something.. Thanks for your help.
I tried Getx and Provider both for this problem, it's problem of referencing of object not the Provider or GetX,
I was coping reference of Objects, list or all data. to Solve this problem, I create clone of each object and then use it.
// COMMON
String? uid;
String? username;
String? fullName;
String? email;
num? timestamp;
List<ProfilePhoto>? photos;
List<String>? skills;
I add one object list and other simple String list
Clone class
MyUser.clone(MyUser? myUser) {
uid = myUser?.uid;
username = myUser?.username;
fullName = myUser?.fullName;
userType = myUser?.userType;
email = myUser?.email;
timestamp = myUser?.timestamp;
photos = ProfilePhoto.cloneList(myUser?.photos);
status = myUser?.status;
skills = [...(myUser?.skills ?? [])];
}
Constructor
MyUser({
this.uid,
this.username,
this.fullName,
this.email,
this.timestamp,
this.photos,
this.skills,)};
Photo class
class ProfilePhoto {
String? id;
String? title;
String? url;
File? file;
bool? isDefault;
ProfilePhoto({
this.id,
this.title,
this.url,
this.file,
this.isDefault,
});
ProfilePhoto.clone(ProfilePhoto profilePhoto) {
id = profilePhoto.id;
title = profilePhoto.title;
url = profilePhoto.url;
file = profilePhoto.file;
isDefault = profilePhoto.isDefault;
}
static List<ProfilePhoto>? cloneList(List<ProfilePhoto>? items) {
if (items == null) return [];
List<ProfilePhoto>? newItems = [];
for (ProfilePhoto item in items) {
newItems.add(ProfilePhoto.clone(item));
}
return newItems;
}
}
Screen layout
#override
void didChangeDependencies() {
super.didChangeDependencies();
final data = _userController.user;
MyUser? user = MyUser.clone(data);
}
void _onChangeDefault(int index) {
ProfilePhoto pp = _profilePhotos[index];
setState(() {
_profilePhotos.removeAt(index);
_profilePhotos.insert(0, pp);
});
}
this may be not a good or optimized solution, but this solve my problem of auto update data in state manager

How can I pass variable id to second screen in flutter?

I have two page and I want to use the variable 'id' in the second screen to fetch data from API.
What should I do?
Screen one: it's the product screen where user click on profile image and after that I get all information about user owner in the second screen.
Screen two: I display data for this user by id
NB: I get all the data by API
id is always Null
Screen one:
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UserProfile(
id: id,
)),
);
// do something here
},
),
Screen two:
class UserProfile extends StatefulWidget {
final int id;
const UserProfile({Key key, #required this.id}) : super(key: key);
#override
_UserProfileState createState() => _UserProfileState();
}
class _UserProfileState extends State<UserProfile> {
#override
void initState() {
getprofile(id);
super.initState();
}
Future<List<dynamic>> getprofile(int id) async {
var response = await Network().getData('/auth/user/$id');
data = json.decode(response.body);
return data;
}
When you want to use a property from the StatefulWidget you need to use widget.propertyName. In your case it's widget.id
class _UserProfileState extends State<UserProfile> {
#override
void initState() {
getprofile(widget.id);
super.initState();
}
Future<List<dynamic>> getprofile(int id) async {
var response = await Network().getData('/auth/user/$id');
data = json.decode(response.body);
return data;
}
Either do the same that you did before,so pass the id as a parameter to the _UserProfileState class, so just call:
_UserProfileState(#required this.id) : super();
Another option to make variables available is to use the Provider widget

Receiving Exception: The getter 'id' was called on null

Hello StackOverflow users,
I got stuck and I am not able to understand why I am receiving this error. So, let me explain me what I am doing,
This is my Home Page where my body of the Scaffold is a PageView, In the PageView the first page is TimeLine(currentUser: currentUser) where currentUser stores the details of the User.
home.dart
Scaffold buildAuthScreen() {
return Scaffold(
body: PageView(
children: [
Timeline(currentUser: currentUser),
ActivityFeed(),
Upload(currentUser: currentUser),
Search(),
Profile(profileId: currentUser?.id),
],
controller: pageController,
onPageChanged: onPageChanged,
physics: NeverScrollableScrollPhysics(),
),
);
}
This is TimeLine Page, in this Page I am just trying to print 'currentUser.id' and while doing that I am receiving the exception (The getter 'id' was called on null).
timeline.dart
class Timeline extends StatefulWidget {
final User currentUser;
Timeline({this.currentUser});
#override
_TimelineState createState() => _TimelineState();
}
class _TimelineState extends State<Timeline> {
#override
Widget build(context) {
print('Timeline : ${widget.currentUser.id}');
return Scaffold(
body: Text('Timeline'),
);
}
}
I was looking up the code to see why I am receiving the exception and then I want to Upload Page, the 3rd page of the PageView and tried to print 'currentUser.id' and interestingly it worked fine here although I am receiving an exception here too but after that the user.id is getting printed..
upload.dart
class Upload extends StatefulWidget {
final User currentUser;
Upload({this.currentUser});
#override
_UploadState createState() => _UploadState();
}
class _UploadState extends State<Upload> {
#override
Widget build(BuildContext context) {
print('Upload : ${widget.currentUser.id}');
return Scaffold(
body: Text('Upload'),
);
}
}
I am confused why this behaviour is happening. If anyone needs more information ping me but I provided the basic structure and I am facing this problem.
<--Update-->
Code where I set currentUser
void createUserInFirestore() async{
/* check if user exists in users.collection in database */
final GoogleSignInAccount user = googleSignIn.currentUser;
DocumentSnapshot doc = await usersRef.doc(user.id).get();
/* If the user doesn't exist then we will create account */
if(!doc.exists) {
final username = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => CreateAccount())
);
/* Create new user from userName in users collection */
usersRef.doc(user.id).set({
"id": user.id,
"username": username,
"photoUrl": user.photoUrl,
"email": user.email,
"displayName": user.displayName,
"bio": "",
"timestamp": timestamp,
});
doc = await usersRef.doc(user.id).get();
}
currentUser = User.fromDocument(doc);
print('Create User in firestore : ${currentUser.id}');
}
}
User model class
class User {
final String id;
final String username;
final String email;
final String photoUrl;
final String displayName;
final String bio;
User({
this.id,
this.username,
this.email,
this.photoUrl,
this.displayName,
this.bio,
});
factory User.fromDocument(doc) {
return User(
id: doc.data()['id'],
username: doc.data()['username'],
email: doc.data()['email'],
photoUrl: doc.data()['photoUrl'],
displayName: doc.data()['displayName'],
bio: doc.data()['bio'],
);
}
}