NativeScript Vue Auth based Navigation - javascript

After trying for hours I gotta ask here, how can I have a simple Auth based Navigation inside my App?
I have a firebase auth user inside my vuex set by a auth listener, all good so far.
Now I simply wanna show the <Main /> screen when the user is signed in, otherwise I wanna show the <sign-in /> screen.
I tried a lot of solutions with v-if, a navigation on creation of the components etc. but did not find any example on how to accomplish this.
How I imagine it how it should work: App.vue
<template>
<Page>
<Frame v-if="user" id="main">
<main />
</Frame>
<Frame v-else>
<sign-in-page />
</Frame>
</Page>
</template>

There is multiple way of approaching this. My prefer way is to create a custom router that uses the $navigateTo or modal navigation. You should see your app as multiple distinct page. Your router then can be something like
let routes = {
navigate(instance, routeName, options) {
return instance.$navigateTo(routeName, options);
}
}
export default routes
then in your components
<script>
import routes from '~/router'; // Path to your router
router.navigate(this, LoginView, {}) // use in methods
</script>
With this basic idea it is possible to add pre and post navigation rules and functions. You can also centralize all the routes and register them. Here it is an import but it can also be a plugins for vue.
You should have 1 login page, 1 loading page, 1 main page, ...
When the app start it always go to the loading where you decide to reroute depending on firebase auth state.

Related

vue3) Google Login Api (GSI)'s redirect mode can't find http://localhost:3000

I want to adjust google login api(GSI) redirect mode. If api complecated, redirect the url to "http://localhost:3000/oauth", post credential token to backend and redirect to "http://localhost:3000".
Here is my code.
<div
id="g_id_onload"
:data-client_id="googleClientId"
data-ux_mode="redirect"
data-auto_prompt="false"
:data-callback="getGoogleLoginCallback"
style="z-index: 100000000000000000"
></div>
<div class="g_id_signin"></div>
After the page redirected and i clicked my account, i got the error http://localhost:3000 is
How can i get page?
I can't find anything method to solve problem
From the docs you can can see that if you doesn't provide data-login_uri attribute, google will redirect to same page where you clicked the login button, if you are planing to post the credintial JWT after login to http://localhost:3000/oauth then the html must be like this
<div
id="g_id_onload"
:data-client_id="googleClientId"
data-ux_mode="redirect"
data-auto_prompt="false"
data-login_uri="http://localhost:3000/oauth"
:data-callback="getGoogleLoginCallback"
style="z-index: 100000000000000000"
></div>
<div class="g_id_signin"></div>
I am not recommending this way of using html in your Vue app, this may not work if the component containing this html is mounted after the library is loaded
Instead Use renderButton function
Instead you can use google.accounts.id.renderButton function to dynamically create a Login Button.
Or Use a Plugin Instead
You can easily do the same using this Vue 3 plugin vue3-google-login which I recently created for easily integrating Login With Google feature in your Vue 3 application, all you need to do is initialise the plugin in main.js with your client id then use the component GoogleLogin like this
<script setup>
const idConfiguration = {
login_uri:'http://localhost:3000/oauth',
ux_mode:'redirect'
}
</script>
<template>
<GoogleLogin
:idConfiguration="idConfiguration"
/>
</template>

Vuejs: shared components used on multiple pages disappeared

right now, I'm writing a single-page-application in vue.js using vue-router. Pages like the homepage, sign-in page etc. all share a navigation and footer component. On a few pages however, I need the entire screen so that the navigation and footer shall not be displayed.
Hence, I decided to nest components and include the navigation and footer component when necessary. My problems now is, that the navigation and footer template disappeared on all pages.
Edit: A more complete demo can be found in this Github repository.
Here's a simplified version of the files I'm using:
index.html:
<div id="app">
<router-view></routerview>
</div>
router.js:
import Homepage from './homepage.vue';
import SignIn from './signin.vue';
const router = new VueRouter({
routes: [
{path: '/', component: Homepage},
{path: '/signin', component: SignIn},
]
})
homepage.vue and signin.vue components:
<template>
<navigation></navigation>
// some page-specific content
<footer-vue></footer-vue>
</template>
<script>
import Navigation from './navigation.vue';
import Footer from './footer.vue';
export default {
components: {
'navigation': Navigation,
'footer-vue': Footer,
},
}
</script>
A component without navigation and footer:
<template>
// some page-specific content
</template>
Is it even possible to nest components this way? I hope someone is able to point me into the right direction.
Both homepage.vue and signin.vue have invalid templates. e.g.
<template>
<navigation></navigation>
<h1>The homepage</h1>
<footer-vue></footer-vue>
</template>
This is not allowed as it has 3 root nodes. See https://v2.vuejs.org/v2/guide/components.html#A-Single-Root-Element
You need to wrap it to get it to work:
<template>
<div>
<navigation></navigation>
<h1>The homepage</h1>
<footer-vue></footer-vue>
</div>
</template>
Note that this limitation does not apply to functional components and is also expected to be lifted for all components in Vue 3.
Much more worrying is that you're not seeing any errors messages for this. You really need to look into that as it suggests there's something very much amiss with your development setup.
An example of the error message you should be seeing:
new Vue({
el: '#app',
template: '<div></div><div></div>'
})
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<div id="app">
</div>

How can I add a script function to React

I am trying to add an external application Chameleon onto my react application and for that I have to add the javascript function to my application.
I only want it to be called in specific situations so I don't want to load it in my index.html. I tried adding it to the render function of my component as:
render() {
return(
<div>
<head>
<script type="text/javascript">/* Chameleon - better user onboarding */!function(t,n,o){var a="chmln",c="setup identify alias track clear set show on off custom help _data".split(" ");n[a]||(n[a]={}),n[a].accountToken=o,n[a].location=n.location.href.toString();for(var e=0;e<c.length;e++)!function(){var t=n[a][c[e]+"_a"]=[];n[a][c[e]]=function(){t.push(arguments)}}();var s=t.createElement("script");s.src="https://fast.trychameleon.com/messo/"+o+"/messo.min.js",s.async=!0,t.head.appendChild(s)}(document,window,"TOKEN");
chmln.identify(USER.ID_IN_DB, { // Unique ID of each user in your database (e.g. 23443 or "590b80e5f433ea81b96c9bf6")
email: USER.EMAIL });
</script>
...
...
</head>
</div>
)
}
But the above doesn't seem to work. I tried the same inside a helmet but no luck. Both of them show an error for
SyntaxError: Unexpected token
Is there a way I can load this function in a specific component or do I have to do it in the index.html?
You seem to have a strong misunderstanding of what react is for and how it is used.
1) There should only ever be 1 head element on the page, and it should be in index.html not in the rendered output of a component.
2) Having a component render a <script> tag goes against the point of using react.
What you need to do is import the code you need into your component:
import './path/to/file.js'
And then from there chmln should be available on the window object
window.chmln.identify()

Two different layouts in aurelia app

I'd like to use two separate layouts for my aurelia app. Difference between them is that one doesn't have a sidebar. Currently I'm using one layout file defined as below:
<template>
<div class="container">
<router-view></router-view>
</div>
</template>
If an active route needs this sidebar to appear I'm just putting it into its view.
What I'd like to achieve is to add another layout that would have this sidebar by default:
<template>
<require from="../common/elements/sidemenu/sidemenu"></require>
<div class="container">
<sidemenu></sidemenu>
<router-view></router-view>
</div>
</template>
So the question is - how to do this? Is it even possible with an aurelia app to have multiple layouts (or master pages, however you call those)?
Use aurelia.setRoot()
You can manually set up your application by specifying a script with configure instructions in your index.html. Typically, this is set to main.
index.html
<body aurelia-app="main">
In this script you can specify a root view model using aurelia.setRoot('root'). If no argument is provided, the convention is to use 'app'.
main.js
aurelia.start().then(() => aurelia.setRoot());
However, you can inject the aurelia object anywhere in your application, and call the setRoot function at any time to load a different root view model.
home.js
#inject(aurelia)
export class HomeViewModel {
constructor(aurelia) {
this.aurelia = aurelia;
}
doStuff() {
this.aurelia.setRoot('withSidebar');
}
}
One common use case for this is having a login page, and I've created a complete template for this use case that you can review, clone, or fork here: http://davismj.me/portfolio/sentry/

How to switch between login page and app with Aurelia

I'm using the Aurelia skeleton for my project. Everything seemed so intuitive, however I'm stuck with a problem which I suspect is fairly easy (if you know how).
The problem is that the app.html / app.js is initially showing a nav bar and loading some default styles.
Now I need a login page, which does not load anything but its own styles, no navbar no nothing - just its own login form.
So I tried something like this:
app.js
<template>
<div if.bind="auth.isNotAuthenticated()">
<require from="components/login/index" ></require>
<login router.bind="router"></login>
</div>
<div if.bind="auth.isAuthenticated()">
<require from="nav-bar.html" ></require>
<require from="../styles/styles.css"></require>
<div class="container" id="banner">
<div class="row">
<img src="images/logo.png" />
</div>
</div>
<nav-bar router.bind="router"></nav-bar>
<div class="page-host">
<router-view></router-view>
</div>
</div>
</template>
Obviously that doesn't work (unless you refresh the page/f5), since the app.js / app.html is the root route which is always present and never changes. But I hope the logic within the markup helps illustrate what I'm looking to solve?
I guess my if only I knew how to reload the parent route (app.js) when I navigate from the login route, on login success, to another route. And again when I logout, the parent route (app.js) should be refreshed as well once again. Then all my problems would be solved.
What am I missing here? :-)
I think aurelia's setRoot(module) function will help with this.
Here's the standard main.js file that "bootstraps" the aurelia app:
main.js
export function configure(aurelia) {
aurelia.use
.standardConfiguration()
.developmentLogging();
aurelia.start()
.then(a => a.setRoot()); // this is the equivalent of setRoot('app')
}
When setRoot is called with no arguments Aurelia looks for an app.js + app.html viewmodel and view.
We can adjust the logic to check whether the user is logged in and if not, show the login screen:
main.js
export function configure(aurelia) {
aurelia.use
.standardConfiguration()
.developmentLogging();
aurelia.start()
.then(a => {
if (userIsLoggedIn()) {
a.setRoot('app');
} else {
a.setRoot('login');
}
});
}
Then in your login view model you can call setRoot('app') after the user has successfully logged in:
login.js
import {Aurelia, inject} from 'aurelia-framework';
import {AuthService} from './my-auth-service';
#inject(Aurelia, AuthService)
export class Login {
userName = '';
password = '';
constructor(aurelia, authService) {
this.aurelia = aurelia;
this.authService = authService;
}
submit() {
// attempt to login and if successful, launch the app view model.
this.authService.login(userName, password)
.then(() => this.aurelia.setRoot('app'));
}
}
Note: if your app includes a "logout" feature that will send the user back to the login screen (eg setRoot('login')), be sure to reset the router and update the url accordingly. This will prevent issues when the user signs back in. More details in here and here.
For a working example of setRoot you can check also
https://foursails.github.io/sentry
https://github.com/foursails/sentry

Categories

Resources