SwiftUI: Publishing single view with data from multiple screens - firebase

Using SwiftUI, I am trying to create an upload onboarding flow, using multiple screens, then storing that data to firebase. Imagine someone uploading their home to airbnb. You have multiple screens in a row (toggled with a back or next button) that gives you an end result of a single, vertically scrolling screen with all of your data that you have previously input.
I have a forum in my app, and have figured out to do this with a single screen of storing data (2 text fields - body and title). But how do I do this for multiple views of data.
I am very very new to programming and have been following a tutorial while trying to mold it to my own thing, so I apologize if the terminology (View, View Model, Model) is incorrect.
Forum code below:
Api:
class Api {
// static var Post = PostApi()
static var User = UserApi()
static var Forum = ForumApi()
}
ForumApi:
class ForumApi {
func uploadForumPost(forumPostTitle: String, forumPostBody: String, imageData: Data, onSuccess: #escaping() -> Void, onError: #escaping(_ errorMessage: String) -> Void) {
guard let userId = Auth.auth().currentUser?.uid else {
return
}
let forumPostId = Ref.FIRESTORE_MY_FORUM_POSTS_DOCUMENT_USERID(userId: userId).collection("userForumPosts").document().documentID
let storageForumPostRef = Ref.STORAGE_FORUM_POST_ID(forumPostId: forumPostId)
let metadata = StorageMetadata()
metadata.contentType = "image/jpg"
StorageService.saveForumPost(userId: userId, forumPostTitle: forumPostTitle, forumPostBody: forumPostBody, forumPostId: forumPostId, imageData: imageData, metadata: metadata, storageForumPostRef: storageForumPostRef, onSuccess: onSuccess, onError: onError)
}
}
Forum Post Model:
struct ForumPost: Encodable, Decodable{
var forumPostTitle: String
var forumPostBody: String
var likes: [String: Bool]
var location: String
var ownerId: String
var postId: String
var username: String
var avatar: String
var mediaUrl: String
var date: Double
var likeCount: Int
}
Forum Post View Model:
class ForumPostViewModel: ObservableObject {
var forumPostTitle: String = ""
var forumCategory: String = ""
var forumPostBody: String = ""
var imageData: Data = Data()
var errorString = ""
#Published var showAlert: Bool = false
func shareForumPost (completed: #escaping() -> Void, onError: #escaping(_ errorMesssage: String) -> Void) {
if !forumPostTitle.isEmpty && !forumPostBody.isEmpty {
//AuthService.signupUser(username: username, email: email, password: password, imageData: imageData, onSuccess: completed, onError: onError)
Api.Forum.uploadForumPost(forumPostTitle: forumPostTitle, forumPostBody: forumPostBody, imageData: imageData, onSuccess: completed, onError: onError)
} else {
showAlert = true
errorString = "Please fill in all fields"
}
}
}
Forum Profile View Model:
class ForumProfileViewModel: ObservableObject {
#Published var userForumPosts: [ForumPost] = []
#Published var isLoading = false
var searchText: String = ""
var splitted: [[ForumPost]] = []
func loadUserForumPosts(userId: String) {
isLoading = true
Api.User.loadForumPosts(userId: userId) { (userForumPosts) in
self.isLoading = false
self.userForumPosts = userForumPosts
self.splitted = self.userForumPosts.splited(into: 1)
}
}
}
Forum Profile View:
struct ForumProfileBody: View {
var userForumPost: ForumPost
#State var shouldSheetShow: Bool = false;
var body: some View {
VStack(alignment: .leading) {
VStack {
HStack {
Text(userForumPost.forumPostTitle)
.fontWeight(.semibold)
.font(.system(size: 22))
Spacer()
Image(systemName: "ellipsis")
}
}
//More UI code
}
}
}

Related

SwiftUI Firebase Phone Auth Change DisplayName

The displayName in the user parameter of the addStateDidChangeListener function in the listener function inside the SessionStore Class returns nil. But I am changing the displayName with the createProfileChangeRequest function. I have one problem. When I change the DisplayName, when I log in with the phone number for the first time, the displayName returns empty. However, when I log in with the application closed in the background, the displayName is full. What is the reason of this ? Where am I doing wrong?
Model:
struct User {
var uid: String
var displayName: String?
var phoneNumber: String?
var isAdmin: Bool
}
Session Store:
class SessionStore : ObservableObject {
var didChange = PassthroughSubject<SessionStore, Never>()
var handle: AuthStateDidChangeListenerHandle?
#Published var user: User?
#Published var uid: String = ""
#Published var errorMessage: String = ""
#Published var showAlert: Bool = false
#Published var isOpenHomePage: Bool = false
#Published var code: String = ""
func listener() {
handle = Auth.auth().addStateDidChangeListener { (auth, user) in
if let user = user {
self.user = User(uid: user.uid, displayName: user.displayName, phoneNumber: user.phoneNumber ?? "", isAdmin: false)
} else {
self.user = nil
}
}
}
func verifyPhoneNumber(phoneNumber: String) {
PhoneAuthProvider.provider().verifyPhoneNumber("+90\(phoneNumber)", uiDelegate: nil) { ID, error in
if error != nil {
self.errorMessage = error?.localizedDescription ?? ""
self.showAlert = true
print("erroroo: \(self.errorMessage)")
return
}
self.uid = ID ?? ""
}
}
func credentialProviderPhoneNumber() {
let credential = PhoneAuthProvider.provider().credential(withVerificationID: uid, verificationCode: code)
Auth.auth().signIn(with: credential) { result, error in
if error != nil {
self.errorMessage = error?.localizedDescription ?? ""
print("error mesajı: \(self.errorMessage)")
return
}
self.isOpenHomePage = true
}
}
func signOut () {
do {
try Auth.auth().signOut()
self.user = nil
} catch {
}
}
func unbind () {
if let handle = handle {
Auth.auth().removeStateDidChangeListener(handle)
}
}
func createProfileChangeRequest() {
let changeRequest = Auth.auth().currentUser?.createProfileChangeRequest()
changeRequest?.displayName = "Test 123"
changeRequest?.commitChanges(completion: { error in
print("hata: \(error?.localizedDescription)")
})
}
}
SignIn View:
struct SignInView: View {
#State var phoneNumber: String = ""
#State var code: String = ""
#State var didGetCode: Bool = false
#EnvironmentObject var session: SessionStore
var body: some View {
NavigationView {
VStack {
TextField("Telefon Numarası", text: $phoneNumber)
.padding(15)
.background(Color(UIColor.secondarySystemBackground))
.cornerRadius(15)
.padding(.horizontal)
.keyboardType(.numberPad)
.opacity(didGetCode ? 0.5 : 1)
.disabled(didGetCode ? true : false)
TextField("Kod", text: $code)
.padding(15)
.background(Color(UIColor.secondarySystemBackground))
.cornerRadius(15)
.padding(.horizontal)
.textContentType(.oneTimeCode)
.keyboardType(.numberPad)
.opacity(didGetCode ? 1 : 0.5)
.disabled(didGetCode ? false : true)
Button(action: {
if code == "" && phoneNumber != "" {
session.verifyPhoneNumber(phoneNumber: phoneNumber)
didGetCode = true
} else {
session.code = code
session.credentialProviderPhoneNumber()
session.createProfileChangeRequest()
}
}) {
Text(didGetCode ? "Doğrula" : "Kod Al")
}
NavigationLink(
destination: HomeView(),
isActive: session.user != nil ? .constant(true) : $session.isOpenHomePage,
label: {
Text("")
})
}
.onAppear {
session.listener()
}
}
}
}
Home View:
struct HomeView: View {
#EnvironmentObject var session: SessionStore
#Environment(\.presentationMode) var presentationMode
var body: some View {
VStack {
Text("Hello User Id: \(session.user?.uid ?? "")")
Text("Tel No: \(session.user?.phoneNumber ?? "")")
Text("Display Name: \(session.user?.displayName ?? "")")
Button(action: {
session.signOut()
presentationMode.wrappedValue.dismiss()
}) {
Text("Çıkış Yap")
}
}
.onAppear {
session.createProfileChangeRequest() -> here
}
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
}
}

How to check if the emaiID exists or not in the dynamodb?

am using node js for the lambda function. I need to check whether the emailID exists or not in the dynamo db...If the emailID exists it should prompt to the user that emailid already exists if not it should store the values in the dynamo db ....
EmailID is the sort key
Customername is the primary key
How can i do that ..
Below is my code:
var doc = require('aws-sdk');
var dynamodb = new doc.DynamoDB()
var tableName = "Testing";
exports.handler = (event, context, callback) => {
var EmailID = event.EmailID; // or any other var which is having emaiID
console.log(event)
var params = {
TableName: "Testing",
Key: { EmailID : "abc#gmail.com",
CustomerName : "ABC"},
AttributeUpdates: {
verified: {
Action: "PUT",
Value: true
}
}
};
// Update the user.
dynamodb.update(params, function(err, data)
{
if (err)
{
console.log(JSON.stringify(err));
context.fail(JSON.stringify(err));
return;
}
context.succeed("User successfully updated.");
});
putItem
var AWS = require('aws-sdk');
var docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = (event, context, callback) => {
// TODO implement
var tableName = "Testing";
console.log(event.EmailID)
var parms = {
TableName : tableName,
Item : {
"EmailID" : event.EmailID,
"CustomerName" : event.CustomerName,
"PersonName" : event.PersonName,
"EmailSent" : event.EmailSent,
"Password" : event.Password
}
};
docClient.put(parms, function(err, data)
{
if (err){
callback(err)
}
else
{
callback(null,"Successfully updated data!!!")
}
})
};
To achieve this I would use the Put operation and use the "exists" parameter. Setting it to false will make sure the put operation will fail if an item already exists. When there is no match then put will insert the record.
For more details on how to use this operation in javascript please check out the documentation:
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html#putItem-property
So in your put example you could add the following to your params:
var AWS = require('aws-sdk');
var docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = (event, context, callback) => {
// TODO implement
var tableName = "Testing";
console.log(event.EmailID)
var parms = {
TableName: tableName,
Item: {
"EmailID": event.EmailID,
"CustomerName": event.CustomerName,
"PersonName": event.PersonName,
"EmailSent": event.EmailSent,
"Password": event.Password
},
ConditionExpression: "attribute_not_exists(EmailID)"
};
docClient.put(parms, function (err, data) {
if (err) {
callback(err)
}
else {
callback(null, "Successfully updated data!!!")
}
})
};

data table (View) not refreshing after jQuery Ajax call in mvc

I'm facing below issue while refreshing data that has been POSTed using Ajax in MVC. The POST is successfully being executed, but the data on the VIEW does not get refreshed with the new data. When I debug, the values from the Ajax POST are successfully being passed to my controller. When the controller returns the view model return View(objLMT);, my VIEW is not refreshing the new data. How do I get the new data to show in my VIEW?
AJAX
function getAllUserRoleCompany() {
debugger
var url = '#Url.Action("GetAllUserRoleCompany", "UserRoleCompany")';
var Organisation = $("#Organisation").val();
if (Organisation == "All") {
Organisation = "";
}
else {
Organisation = Organisation;
}
var RoleName = $("#RoleName").val();
if (RoleName == "All") {
RoleName = "";
}
else {
RoleName = RoleName;
}
var i = 0;
if ($("#UserName").find("option:selected").length >= 0) {
var len = $("#UserName").find("option:selected").length;
}
else {
len = 0;
}
var UserName = "";
for (; i < len; i++) {
if ($("#UserName").find("option:selected")[i].text != "All") {
if (i == 0) {
UserName = "',";
}
if (i < len - 1) {
UserName += $("#UserName").find("option:selected")[i].text + ",";
UserName = UserName.substring(0, UserName.indexOf("-")) + ",";
}
else {
UserName += $("#UserName").find("option:selected")[i].text + ",'";
UserName = UserName.substring(0, UserName.indexOf("-")) + ",'";
}
}
}
if (UserName == "All") {
UserName = ""
}
else {
UserName = UserName;
}
var UserStatus = $("#UserStatus").val();
if (UserStatus == "All") {
UserStatus = "";
}
else {
UserStatus = UserStatus;
}
$.ajax({
url: url,
data: { Organisation: Organisation, RoleName: RoleName, UserName: UserName, UserStatus: UserStatus },
cache: false,
type: "POST",
success: function (data) {
//$("#dataTables-example").bind("");
//$("#dataTables-example").bind();
//location.reload(true);
},
error: function (reponse) {
alert("error : " + reponse);
}
});
Below is the view code on the same page
<div class="row">
#Html.Partial("pv_UserRoleCompany", Model)
Controller
public ActionResult GetAllUserRoleCompany(String Organisation, String RoleName, String UserName, int UserStatus)
{
LMTUsage objLMT = new LMTUsage();
LMTDAL objLMTDAL = new LMTDAL();
string usrNameWithDomain = System.Web.HttpContext.Current.User.Identity.Name;
//string userID = "261213"; // Environment.UserName;
string userID = "100728";
ViewBag.UserRoleId = objLMTDAL.GetRoleID(userID);
objLMT.TypeList = objLMTDAL.UserRoleCompany_GetAll(Organisation, RoleName, userID, ViewBag.UserRoleId, UserName, UserStatus);
// return Json(objLMT, JsonRequestBehavior.AllowGet);
return PartialView("pv_UserRoleCompany", objLMT);
}
With above code My while SEARCHING or UPDATING view my table/Grid is not refreshing.
Kindly help.
If you are returning a partial view from an AJAX call you have to use jQuery to "refresh" the data.
In your js code you can do this:
$.ajax({
url: url,
data: { Organisation: Organisation, RoleName: RoleName, UserName: UserName,
UserStatus: UserStatus },
cache: false,
type: "POST",
success: function (data) {
//$("#dataTables-example").bind("");
//$("#dataTables-example").bind();
//location.reload(true);
$("#dataTables-example").html(data);
},
error: function (reponse) {
alert("error : " + reponse);
}
});
This will replace the existing HTML with the one from the partial view result in your controller.
#Mihail I have tried using the above solution. It Works I mean it refreshes my view but It's not loading my view perfectly as expected.
View Before (Expected)
View After using $("#dataTables-example").html(data);
Try if this works for you
Call this function as per your call:
function getAllUserRoleCompany(parameters) {
var token = $('[name=__RequestVerificationToken]').val();
$.ajax({
type: "POST",
url: '/UserRoleCompany/GetAllUserRoleCompany',
data: { Organisation: Organisation, RoleName: RoleName, UserName: UserName, UserStatus: UserStatus },
dataType: 'html',
success: function (data) {
$("#").empty().html(data);
}
});
}

FS.Collection Image ID don't validate check()

I'm trying to save image id after insert in FS.Collection.
Insert array
var item = {
name: $(value).find('#name').val(),
article: $(value).find('#article').val(),
description: $(value).find('#description').val(),
price: $(value).find('#price').val(),
sizes: $(value).find('#sizes').val()
};
file = $(value).find('#attachmentName')[0].files[0];
if (file !== undefined) {
Images.insert(file, function (err, fileObj) {
item = _.extend(item, {
image: fileObj._id.toString()
});
});
}
Meteor.call('collectionInsert', item, function(error, result) {
if (error)
return alert(error.reason);
Router.go('collection', {_id: result._id});
});
collectionInsert method
Meteor.methods({
collectionInsert: function(postAttributes) {
check(Meteor.userId(), String);
check(postAttributes, {
name: String,
article: String,
description: String,
price: String,
sizes: String,
image: String
});
var user = Meteor.user();
var post = _.extend(postAttributes, {
userId: user._id,
author: user.profile.name,
timestamp: new Date(),
views: 0
});
var collectionId = Collections.insert(post);
return {
_id: collectionId
};
}
});
Then i'm got Exception
Exception while invoking method 'collectionInsert' Error: Match error: Missing key 'image'
In console log i have item value
...
image: "4J55dyGb5DpqbCXGG"
...
I'm trying to change check property to image: Match.Optional([String]) and image: Match.Any - no effect
I think the issue here is that your insert method is non-blocking, which means that you probably haven't received the fileObj nor extended item before passing it to the method call. Maybe you should try to make the method call in the insert callback, like this:
if (file !== undefined) {
Images.insert(file, function (err, fileObj) {
item.image = fileObj._id.toString(); // don't need _.extend
// item should now be extended
Meteor.call('collectionInsert', item, function(error, result) {
if (error)
return alert(error.reason);
Router.go('collection', {_id: result._id});
});
});
}
By the way, you should probably store the result of $(value) instead of constructing the same jQuery object over and over. Just a minor optimization, but improves readability nonetheless.
var $value = $(value);
var item = {
name: $value.find('#name').val(),
...
};

Keep login infomation after login in sencha touch 2

I make an small web-application using Sencha touch 2. I have already done with login page. The purpose of second page is get current User session who post Products. This is login page
onSignInCommand: function (view, username, password) {
var me = this;
var loginView = this.getLoginView();
if (username.length == 0 || password.length == 0) {
loginView.showSignInMessage("Please enter your username and password.");
return;
}
loginView.setMasked({
xtype: "loadmask",
message:"Signing in..."
});
//Set ajax
Ext.Ajax.request({
url: "./ajax/Account.ashx",
params: {
type: "login",
username: username,
password: password
},
success: function (response) {
var loginResponse = Ext.JSON.decode(response.responseText);
if (loginResponse.success) {
me.sessionToken = loginResponse.sessionToken;
me.showSignInSuccess();
} else {
me.sessionToken = null;
me.showSignInFailedMessage(loginResponse.message);
}
},
failure: function () {
me.sessionToken = null;
me.showSignInFailedMessage('Login failed. Please try again later.');
}
});
}
And server-side:
private void Login(HttpContext context)
{
var resultStt = "";
var userid = context.Request["username"];
var password = context.Request["password"];
if(!string.IsNullOrEmpty(userid) && !string.IsNullOrEmpty(password))
{
var user = new Select() .From<User>()
.Where("UserID").IsEqualTo(userid)
.And("UserPassword").IsEqualTo(password)
.ExecuteSingle<User>();
if(user!=null)
{
context.Session.Add("PickerUser",user);
resultStt = " {\"success\":true, \"user\":{ \"userId\":"+user.UserID+", \"sessionId\":\"" + context.Session.SessionID + "\"}}";
}
else
{
resultStt = " {\"success\":false, \"message\":\"Login failed. Please enter the correct credentials.\"}";
}
}
context.Response.Write(resultStt);
}
The second page that i need get a list procducts created by user
store: {
autoload:true,
...
proxy: {
type: "ajax",
url: "./ajax/process.ashx?type=loadassigned",
reader:{
type:"json",
rootProperty: "data"
}
}
},
Can not get session because the ajax was loaded at the time of startup app
var currenUser = context.Session["PickerUser"] as User;
You could remove the config:
autoLoad: true
And call this in your login success handler function:
Ext.getStore('yourStoresId').load({
callback: function() {
console.log('my store has loaded');
}
});

Resources