Passing variables between functions on the same screen - firebase

Here you can see the variable called ChatID.
getChatId() {
const IDloc = firebase.database().ref('/rooms');
const newChat = IDloc.push({
title: 'New chat over again'
});
const ChatID = newChat.key;
try {
AsyncStorage.getItem('email').then((email) => {
const membersList = firebase.database().ref('/members').child(ChatID);
const user1 = email
console.log('user1: ', user1);
const user = firebase.auth().currentUser;
membersList.set({
user1: user1,
user2: user.email
});
}).done();
} catch (error) {
console.log('Error has accurated');
}
}
get ref() {
return firebase.database().ref('/messages').child(this.getChatId.ChatID);
}
What I need to do is to pass this variable from getChatId() to ref() and insert this ChatID inside of child.
When I do this the way I did in my code I get undefined instead of ChatID. When I try to do this with state={}, then I just get null.
How can I fix it?

If you are using a class you can do the following
ChatID = '' //declare the variable outside
getChatId() {
const IDloc = firebase.database().ref('/rooms');
const newChat = IDloc.push({
title: 'New chat over again'
});
this.ChatID = newChat.key; //set the variable
try {
AsyncStorage.getItem('email').then((email) => {
const membersList = firebase.database().ref('/members').child(ChatID);
const user1 = email
console.log('user1: ', user1);
const user = firebase.auth().currentUser;
membersList.set({
user1: user1,
user2: user.email
});
}).done();
} catch (error) {
console.log('Error has accurated');
}
}
get ref() {
return firebase.database().ref('/messages').child(this.ChatID);
}

Related

Get content related to a user in Strapi

I have a collection in Strapi called projects and I want to be able to fetch only the projects belonging to the currently logged in user. I'm using Next.js with NextAuth on the frontend and I'm currently filtering the results using:
/api/projects?filters[user][id][$eq]=${session.id}
This works fine except the endpoint still allows a user to fetch projects for all users if accessed directly. I'm thinking a better approach would be to setup a custom API endpoint in Strapi which would be something like /api/projects/:user. Is this the best way to acheive this? I've managed to setup a custom endpoint in Strapi using the CLI but I'm not sure what logic needs to go in the controller. Would modifiying an exisiting endpoint be better?
Any advice appreciated, thanks!
Custom endpoint create is good idea. I had same problem. Once i created custom endpoint then i got data with entitiyservice. It's work. Below image is my code.
./scr/api/[collection]/controllers/[collection].js
'use strict';
const { createCoreController } = require('#strapi/strapi').factories;
module.exports = createCoreController('api::user-profile.user-profile', ({ strapi }) => ({
async me(ctx) {
try {
const user = ctx.state.user;
const datas = await strapi.entityService.findMany("api::user-profile.user-profile", {
filters: {
user: {
id: user.id
}
}
})
return datas;
} catch (err) {
ctx.body = err;
}
}
}));
If you will use all endpoints in collection like (create,update,delete,find,findone). You must override the all endpoints . Example is the below.
'use strict';
const { createCoreController } = require('#strapi/strapi').factories;
module.exports = createCoreController('api::education.education', ({ strapi }) => ({
async create(ctx) {
try {
const user = ctx.state.user;
ctx.request.body.data.users_permissions_user = user.id
const datas = await strapi.entityService.create("api::education.education", {
...ctx.request.body
})
return datas;
} catch (err) {
ctx.body = err;
}
},
async update(ctx) {
try {
const user = ctx.state.user;
ctx.request.body.data.users_permissions_user = user.id
const { id } = ctx.params;
const experienceData = await strapi.entityService.findMany("api::education.education", {
filters: {
users_permissions_user: {
id: user.id
},
id: id
}
});
if (experienceData.length === 0) {
return {
data: null,
error: {
message: ''
}
}
}
const datas = await strapi.entityService.update("api::education.education", id, {
...ctx.request.body
})
return datas;
} catch (err) {
ctx.body = err;
}
},
async delete(ctx) {
try {
const user = ctx.state.user;
const { id } = ctx.params;
const experienceData = await strapi.entityService.findMany("api::education.education", {
filters: {
users_permissions_user: {
id: user.id
},
id: id
}
});
if (experienceData.length === 0) {
return {
data: null,
error: {
message: ''
}
}
}
const datas = await strapi.entityService.delete("api::education.education", id)
return datas;
} catch (err) {
ctx.body = err;
}
},
async findOne(ctx) {
try {
const user = ctx.state.user;
const { id } = ctx.params;
const experienceData = await strapi.entityService.findMany("api::education.education", {
filters: {
users_permissions_user: {
id: user.id
},
id: id
}
});
if (experienceData.length === 0) {
return {
data: null,
error: {
message: ''
}
}
}
const datas = await strapi.entityService.findOne("api::education.education", id)
return datas;
} catch (err) {
ctx.body = err;
}
},
async find(ctx) {
try {
const user = ctx.state.user;
const datas = await strapi.entityService.findMany("api::education.education", {
filters: {
users_permissions_user: {
id: user.id
}
}
})
return datas;
} catch (err) {
ctx.body = err;
}
},
}));
No extra endpoints and no extra codes.
Strapi v4
Yes, creating separate endpoint for this task would be great.
Instead of /api/projects/:user using this type of route, use /api/projects as you can get current logged in users details from ctx.state.user
No, Instead of modifying your existing controller create new controller and use that controller to satisfy your needs.
I ended up extending my controller. In src/api/controllers/project.js I made the following changes:
"use strict";
const { createCoreController } = require("#strapi/strapi").factories;
module.exports = createCoreController("api::project.project", {
async find(ctx) {
const user = ctx.state.user;
ctx.query.filters = {
...(ctx.query.filters || {}),
user: user.id,
};
return super.find(ctx);
},
});
Then simply call the /api/projects endpoint.
Answer based on this guide Limit access of Strapi users to their own entries.

Adding update property to mutation function breaks mocked result in MockProvider

I've got the following function that gets triggered on a form submission
const [register, { loading }] = useMutation(RegisterDocument);
const router = useRouter();
const onSubmit = async (values: FormValues) => {
const v = { ...values };
delete v.confirmPassword;
const res = await register({
variables: { options: v },
update: (cache, { data }) => {
cache.writeQuery<MeQuery>({
query: MeDocument,
data: {
__typename: 'Query',
me: data?.register.user,
},
});
},
});
if (res.data?.register.user) {
router.push('/');
}
};
I then have the following test to submit the form
test('it should submit form without error', async () => {
const firstName = faker.name.firstName();
const surname = faker.name.lastName();
const username = faker.internet.userName().replace('#', '');
const email = faker.internet.email();
const password = faker.internet.password(6, false, /^[a-zA-Z0-9_.-]*$/);
const cache = new InMemoryCache().restore({});
const variables = {
options: { email, firstName, password, surname, username },
};
const user = { email, firstName, surname, username, id: 1, activated: false, photo: null };
const mocks = [
{
request: { query: RegisterDocument, variables },
result: { data: { register: { errors: null, user } } },
},
];
const { queryByTestId, container } = renderWithTheme(
<MockedProvider mocks={mocks} cache={cache}>
<Register />
</MockedProvider>,
);
await updateRegisterInputs(container); // util function that updates input values for submission
await submitForm({ queryByTestId, testId: 'register-submit', loadingTestId: 'register-loading' }); // util function that submits form
await waitFor(() => expect(onPush).toBeCalledWith('/'));
});
When I run this test res returns the following
{ data: { register: {} } }
However, once I remove the update property inside the register mutation function, res returns the following.
{ data: { register: { errors: null, user: [Object] } } }
Any ideas why the mocked return value returns an empty object for the register property only when the update property function is added?
Even just instantiating the update property like so;
update: () => {}
still breaks the response from the mutation.
I realised that the graphql doc required the __typename property in the relevant places in my mocks
So I have to update the mock to include the typenames.
const user = { email, firstName, surname, username, id: 1, activated: false, photo: null, __typename: 'User' };
const mocks = [
{
request: { query: RegisterDocument, variables },
result: { data: { register: { errors: null, user, __typename: 'UserResponse' } } },
},
];

Maximum call stack size exceeded( in Nuxt + Firebase Project)

I'm currently creating an authentication feature in Nuxt and Firebase.
The login and logout process itself can be done and the header display changes accordingly, but there is an error in console when I press the login button.
Error content (in console)
Uncaught RangeError: Maximum call stack size exceeded
at Function.keys (<anonymous>)
code
Header.vue(This is the page containing the login button.)↓
googleLogin () {
const provider = new firebase.auth.GoogleAuthProvider()
auth.signInWithPopup(provider)
.then(res => {
this.dialogAuthVisible = false
this.$store.dispatch('auth/setUser',res.user)
}).catch(e => console.log(e))
}
store/auth.js↓
export const strict = false
export const state = () => ({
user: null
})
export const mutations = {
SET_USER (state, payload) {
state.user = payload
}
}
export const actions = {
setUser ({ commit }, user) {
commit('SET_USER',user)
}
}
export const getters = {
isAuthenticated (state) {
return !!state.user
}
}
default.vue↓
mounted () {
auth.onAuthStateChanged(user => {
const { uid, displayName, photoURL} = user
if (user) {
this.$store.dispatch('auth/setUser', { uid, displayName, photoURL})
} else {
this.$store.dispatch('auth/setUser', null)
}
})
}
If there's any information I'm missing, please let me know 🙇️.
Please teach me how to do this 🙇️.
I think the problem is in this code lines :
export const mutations = {
SET_USER (state, payload) {
state.user = payload
}
}
export const actions = {
setUser ({ commit }, user) {
commit('SET_USER',user)
}
}
There is a loop between this mutations and actions
Instead of setting the entire payload into the store object, I just picked the fields I needed, and that resolved the problem for me.
Before:
AUTH_STATUS_CHANGED ({commit}, data: any): any {
if (data && data.authUser) {
commit('SetAuthUser', data.authUser);
} else {
commit('SetAuthUser', null);
}
}
After:
AUTH_STATUS_CHANGED ({commit}, data: any): any {
if (data && data.authUser) {
const user = data.authUser;
commit('SetAuthUser', {
uid: user.uid,
email: user.email,
emailVerified: user.emailVerified,
displayName: user.displayName,
isAnonymous: user.isAnonymous,
photoURL: user.photoURL,
stsTokenManager: user.stsTokenManager,
createdAt: user.createdAt,
lastLoginAt: user.lastLoginAt,
apiKey: user.apiKey,
});
} else {
commit('SetAuthUser', null);
}
}
Inside the mutation, just add the value received from the mutation payload.

How to use chained promises inside firebase functions?

I created a firebase function that updates the like count of an comment or post when a new like document is created.
But it throws an 404 error.
exports.updateLikeCount = functions.firestore
.document('likes')
.onCreate((snap, context) => {
const likeObj = snap.data();
if(likeObj.isComment) {
const { _comment } = likeObj;
const commentRef = fstore.collection('comments').doc(_comment);
return commentRef.get()
.then(doc => {
let { likes } = doc.data();
++likes;
return commentRef.update({
likes
});
});
}else {
const { _post } = likeObj;
const postRef = fstore.collection('posts').doc(_post);
return postRef.get()
.then(doc => {
let { likes } = doc.data();
++likes;
return postRef.update({
likes
});
});
}
});
NOTE:
_post and _comment are post ID and comment ID respectively

Sending data to an imported module in React Native

I have a module called Chat.js that imports Fire.js in order to send data (message comes into Chat.js, and Fire.js handles storage).
I have a recipient's user ID that is only currently available in Chat.js, but it is important to get to Fire.js in order to store appropriately.
I removed some info for brevity, this is my current Chat.js:
import Fire from './Fire';
class Chat extends React.Component<Props> {
state = {
messages: [],
};
get user() {
return {
name: this.props.navigation.state.params.name,
_id: Fire.shared.uid,
};
}
render() {
return (
<GiftedChat
messages={this.state.messages}
onSend={Fire.shared.send}
user={this.user}
/>
);
}
componentDidMount() {
Fire.shared.on(message =>
this.setState(previousState => ({
messages: GiftedChat.append(previousState.messages, message),
}))
);
}
componentWillUnmount() {
Fire.shared.off();
}
}
export default Chat;
And this is my current Fire.js:
import firebase from 'react-native-firebase';
class Fire {
constructor() {
}
get ref() {
var recipient = 'recipientId'
return firebase.database().ref('messages/' + this.uid + '/' + recipient);
}
parse = snapshot => {
const { timestamp: numberStamp, text, user } = snapshot.val();
const { key: _id } = snapshot;
const timestamp = new Date(numberStamp);
const message = {
_id,
timestamp,
text,
user,
};
return message;
};
on = callback =>
this.ref
.limitToLast(20)
.on('child_added', snapshot => callback(this.parse(snapshot)));
// send the message to the Backend
send = messages => {
for (let i = 0; i < messages.length; i++) {
const { text, user } = messages[i];
const message = {
text,
user,
timestamp: this.timestamp,
};
this.append(message);
}
};
append = message => this.ref.push(message);
// close the connection to the Backend
off() {
this.ref.off();
}
}
Fire.shared = new Fire();
export default Fire;
I currently need to get the recipient ID, which is available in chat.js under
this.props.navigation.state.params.uid
Into the Fire.js lines:
get ref()
{
var recipient = 'recipientId'
I can't seem to get this uid into get ref()
Use getter and setters in Fire.js.
In Fire.js
setRecipient (id){
this.recipientId = id;
}
get getRecipientId () {
return this.recipientId;
}
And then call Fire.setRecipient(yourId) in Chat.js.

Resources