rapid_stack 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/lib/rapid_stack/generators/generator-rapid/bin/rapid.js +4 -0
  4. data/lib/rapid_stack/generators/generator-rapid/generators/build-fullstack/index.js +18 -0
  5. data/lib/rapid_stack/generators/generator-rapid/generators/frontend-auth/templates/pages/signup/signup.page.ts.ejs +22 -5
  6. data/lib/rapid_stack/generators/generator-rapid/generators/frontend-company/index.js +68 -0
  7. data/lib/rapid_stack/generators/generator-rapid/generators/frontend-company/templates/src/app/company/company-registration.page.html +53 -0
  8. data/lib/rapid_stack/generators/generator-rapid/generators/frontend-company/templates/src/app/company/company-registration.page.scss +56 -0
  9. data/lib/rapid_stack/generators/generator-rapid/generators/frontend-company/templates/src/app/company/company-registration.page.ts +114 -0
  10. data/lib/rapid_stack/generators/generator-rapid/generators/frontend-home/index.js +37 -0
  11. data/lib/rapid_stack/generators/generator-rapid/generators/frontend-home/templates/src/app/home/home.page.html +45 -0
  12. data/lib/rapid_stack/generators/generator-rapid/generators/frontend-home/templates/src/app/home/home.page.scss +94 -0
  13. data/lib/rapid_stack/generators/generator-rapid/generators/frontend-home/templates/src/app/home/home.page.ts +35 -0
  14. data/lib/rapid_stack/generators/generator-rapid/generators/graphql/templates/graphql/create.mutation.ts.ejs +1 -1
  15. data/lib/rapid_stack/generators/generator-rapid/generators/graphql/templates/graphql/delete.mutation.ts.ejs +1 -1
  16. data/lib/rapid_stack/generators/generator-rapid/generators/graphql/templates/graphql/list.query.ts.ejs +1 -1
  17. data/lib/rapid_stack/generators/generator-rapid/generators/graphql/templates/graphql/show.query.ts.ejs +1 -1
  18. data/lib/rapid_stack/generators/generator-rapid/generators/graphql/templates/graphql/update.mutation.ts.ejs +1 -1
  19. data/lib/rapid_stack/post_install.rb +4 -0
  20. data/lib/rapid_stack/pre_install.rb +52 -0
  21. data/lib/rapid_stack/version.rb +1 -1
  22. metadata +32 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 639708209d08d8418f5165a53fc1d46f661769fcacfeff38a19c5b0ad935ef47
4
- data.tar.gz: b99886d52fb715b37a9eeacd4e39205997acd462dbc160b0cf2a822ed392351c
3
+ metadata.gz: a0f811ef1816391b9f0efbb459a472d19735071288c70b214e2d84e65bb4b866
4
+ data.tar.gz: bd85ce600a38b610fd60754bce4d88ddefa537e47d4644425b8f44cb251450b0
5
5
  SHA512:
6
- metadata.gz: e42d028b9e77405fb91f3782736488f2695917a24c41ff9a9cdfb979912a5848e5e05c4f4153a2b64db1a9ca9b9c29b496820f45ff96adac63ebc7ea82c5d6ba
7
- data.tar.gz: 893d39cc8485271e2abfc84a80b417e9b4077e19fb163083370d8afccc1d8b3a97bafb2d0c714d077e985bd397cbf9f9c93b0373ea06cd3287afae751e58a712
6
+ metadata.gz: 23ca2a82b234bb502fd825cb21ea77eb6f46e7cdcc362b5de34d67e4b0cbf93f017cced1e429a41a70fa347c489d8a45314d76b6aec19c1184a206e46864676e
7
+ data.tar.gz: 647787a1ac4904a82e4acbfe2fd5c76bbbf3004b9f35818c4ac64ac1e2be48ea78e63f1de127a861d1fba95d0b901fad915e15b094b6eeed7804aebdf531e7d3
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## [1.0.4] - 2025-04-03
2
+ ### Added
3
+ - Ability to generate company with frontend:company
4
+
5
+ ## [1.0.4] - 2025-04-03
6
+ ### Added
7
+ - Ability to generate company with frontend:company
8
+
1
9
  ## [1.0.3] - 2025-04-02
2
10
  ### Added
3
11
  - build graphql as part of fullstack generator
@@ -45,6 +45,8 @@ if (!command) {
45
45
  console.error(' frontend:auth - Add authentication');
46
46
  console.error(' frontend:event - Add event handling');
47
47
  console.error(' frontend:list - Add list actions');
48
+ console.error(' frontend:home - Add home page');
49
+ console.error(' frontend:company - Add company page');
48
50
  console.error(' frontend:platform:rm - Remove frontend platform');
49
51
  console.error(' frontend:auth:rm - Remove frontend authentication');
50
52
 
@@ -80,6 +82,8 @@ const generatorMap = {
80
82
  'frontend:platform': '../generators/frontend-platform',
81
83
  'frontend:crud': '../generators/frontend-crud',
82
84
  'frontend:auth': '../generators/frontend-auth',
85
+ 'frontend:home': '../generators/frontend-home',
86
+ 'frontend:company': '../generators/frontend-company',
83
87
  'frontend:auth:rm': '../generators/remove-frontend-auth',
84
88
  'frontend:event': '../generators/frontend-event',
85
89
  'frontend:list': '../generators/frontend-list-action',
@@ -79,6 +79,24 @@ module.exports = class extends Generator {
79
79
  process.exit(1);
80
80
  }
81
81
 
82
+ this.log('\nBuild frontend company...');
83
+ try {
84
+ execSync('rapid frontend:company --yes --force', { stdio: 'inherit' });
85
+ this.log('✓ Frontend company created successfully');
86
+ } catch (error) {
87
+ this.log.error('Failed to create frontend company:', error);
88
+ process.exit(1);
89
+ }
90
+
91
+ this.log('\nBuild frontend home...');
92
+ try {
93
+ execSync('rapid frontend:home --yes --force', { stdio: 'inherit' });
94
+ this.log('✓ Frontend home created successfully');
95
+ } catch (error) {
96
+ this.log.error('Failed to create frontend home:', error);
97
+ process.exit(1);
98
+ }
99
+
82
100
  this.log('\n✓ Fullstack application created successfully!');
83
101
  }
84
102
 
@@ -1,7 +1,7 @@
1
1
  import { Component, OnInit } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import { ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
4
- import { RouterLink } from '@angular/router';
4
+ import { RouterLink, ActivatedRoute } from '@angular/router';
5
5
  import { CreateUserMutation } from 'src/app/graphql/mutations/auth/createUser.mutation';
6
6
  import { Router } from '@angular/router';
7
7
  import { BaseGraphQLPage } from 'src/app/shared/base/base-graphql.page';
@@ -50,19 +50,30 @@ export class SignupPage extends BaseGraphQLPage implements OnInit {
50
50
 
51
51
  constructor(
52
52
  private formBuilder: FormBuilder,
53
- private router: Router
53
+ private router: Router,
54
+ private route: ActivatedRoute
54
55
  ) {
55
56
  super();
56
57
  this.signupForm = this.formBuilder.group({
57
58
  <% args.filter(arg => arg.name !== 'encrypted_password' && arg.name !== 'role').forEach(function(arg) { %>
58
- <%= snakeToCamel(arg.name) %>: ['', [<%= arg.required ? 'Validators.required' : '' %><%= arg.type === 'String' ? ', Validators.minLength(3)' : '' %>]],
59
+ <%- snakeToCamel(arg.name) %>: [<%- arg.type === 'Boolean' ? false : '\'\'' %>, [<%- arg.required ? 'Validators.required' : '' %><%- arg.type === 'String' ? ', Validators.minLength(3)' : '' %><%- arg.type === 'Boolean' ? ', Validators.pattern(/^(true|false)$/)' : '' %><%- arg.name === 'accept_terms' ? ', Validators.requiredTrue' : '' %>]],
59
60
  <% }); %>
60
61
  }, {
61
62
  validators: this.passwordMatchValidator
62
63
  });
63
64
  }
64
65
 
65
- ngOnInit() {}
66
+ ngOnInit() {
67
+ // Get company code from query params
68
+ this.route.queryParams.subscribe(params => {
69
+ const companyCode = params['companyCode'];
70
+ if (companyCode) {
71
+ const companyCodeControl = this.signupForm.get('companyCode');
72
+ companyCodeControl?.setValue(companyCode);
73
+ companyCodeControl?.disable();
74
+ }
75
+ });
76
+ }
66
77
 
67
78
  // Custom validator for password match
68
79
  private passwordMatchValidator(form: FormGroup) {
@@ -86,7 +97,11 @@ export class SignupPage extends BaseGraphQLPage implements OnInit {
86
97
  this.backendErrors = [];
87
98
 
88
99
  if (this.signupForm.valid) {
89
- const signupData = this.signupForm.value;
100
+ // Get both enabled and disabled form values
101
+ const signupData = {
102
+ ...this.signupForm.value,
103
+ companyCode: this.signupForm.get('companyCode')?.value
104
+ };
90
105
 
91
106
  this.executeMutation({
92
107
  mutation: CreateUserMutation,
@@ -120,9 +135,11 @@ export class SignupPage extends BaseGraphQLPage implements OnInit {
120
135
  if (formControl.errors['pattern']) {
121
136
  if (control === 'password') return 'Please include a number and a special character';
122
137
  if (control === 'telephone') return 'Please enter a valid phone number';
138
+ if (formControl.errors['pattern'].requiredPattern === '/^(true|false)$/') return 'Must be a valid boolean value';
123
139
  return 'Invalid format';
124
140
  }
125
141
  if (formControl.errors['passwordMismatch']) return 'Passwords do not match';
142
+ if (formControl.errors['requiredTrue']) return 'You must accept the terms and conditions';
126
143
 
127
144
  return '';
128
145
  }
@@ -0,0 +1,68 @@
1
+ const Generator = require('yeoman-generator');
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+
5
+ module.exports = class extends Generator {
6
+ constructor(args, opts) {
7
+ super(args, opts);
8
+ this.frontendPath = 'frontend';
9
+ }
10
+
11
+ async writing() {
12
+ const targetPath = path.join(this.frontendPath, 'src/app/company');
13
+
14
+ // Copy the template files
15
+ this.fs.copyTpl(
16
+ this.templatePath('src/app/company/company-registration.page.html'),
17
+ this.destinationPath(path.join(targetPath, 'company-registration.page.html'))
18
+ );
19
+
20
+ this.fs.copyTpl(
21
+ this.templatePath('src/app/company/company-registration.page.scss'),
22
+ this.destinationPath(path.join(targetPath, 'company-registration.page.scss'))
23
+ );
24
+
25
+ this.fs.copyTpl(
26
+ this.templatePath('src/app/company/company-registration.page.ts'),
27
+ this.destinationPath(path.join(targetPath, 'company-registration.page.ts'))
28
+ );
29
+
30
+ // Update app.routes.ts
31
+ const routesPath = path.join(this.frontendPath, 'src/app/app.routes.ts');
32
+ if (fs.existsSync(routesPath)) {
33
+ let routesContent = fs.readFileSync(routesPath, 'utf8');
34
+
35
+ // Check if the route already exists
36
+ if (routesContent.includes('path: \'company-registration\'')) {
37
+ this.log('Company registration route already exists in app.routes.ts');
38
+ return;
39
+ }
40
+
41
+ // Find the routes array
42
+ const routesArrayMatch = routesContent.match(/export const routes:\s*Routes\s*=\s*\[([\s\S]*?)\];/);
43
+
44
+ if (routesArrayMatch) {
45
+ const existingRoutes = routesArrayMatch[1];
46
+ const newRoute = `
47
+ {
48
+ path: 'company-registration',
49
+ loadComponent: () => import('./company/company-registration.page').then((m) => m.CompanyRegistrationPage),
50
+ },`;
51
+
52
+ // Insert the new route at the beginning of the routes array
53
+ const updatedRoutes = routesContent.replace(
54
+ /export const routes:\s*Routes\s*=\s*\[/,
55
+ `export const routes: Routes = [${newRoute}`
56
+ );
57
+
58
+ // Write the updated content back to the file
59
+ fs.writeFileSync(routesPath, updatedRoutes);
60
+ this.log('Updated app.routes.ts with company registration route');
61
+ } else {
62
+ this.log('Could not find routes array in app.routes.ts');
63
+ }
64
+ } else {
65
+ this.log('app.routes.ts not found');
66
+ }
67
+ }
68
+ };
@@ -0,0 +1,53 @@
1
+ <ion-header>
2
+ <ion-toolbar color="primary">
3
+ <ion-buttons slot="start">
4
+ <ion-back-button defaultHref="/"></ion-back-button>
5
+ </ion-buttons>
6
+ <ion-title>Register Company</ion-title>
7
+ </ion-toolbar>
8
+ </ion-header>
9
+
10
+ <ion-content class="ion-padding">
11
+ <div class="company-registration-container">
12
+ <form [formGroup]="companyForm" (ngSubmit)="onSubmit()" class="company-form">
13
+ <!-- Company Name -->
14
+ <ion-item class="form-field">
15
+ <ion-label position="floating">Company Name</ion-label>
16
+ <ion-input
17
+ type="text"
18
+ formControlName="name"
19
+ [class.ion-invalid]="isSubmitted && f['name'].errors"
20
+ [class.ion-touched]="isSubmitted && f['name'].errors"
21
+ ></ion-input>
22
+ </ion-item>
23
+ <ion-text color="danger" class="error-message" *ngIf="isSubmitted && f['name'].errors">
24
+ {{ getErrorMessage('name') }}
25
+ </ion-text>
26
+
27
+ <!-- Backend Errors -->
28
+ <ion-item lines="none" *ngIf="backendErrors?.length" class="status-messages error-messages">
29
+ <ion-text color="danger">
30
+ <ng-container *ngFor="let error of backendErrors">
31
+ <p>{{ error }}</p>
32
+ </ng-container>
33
+ </ion-text>
34
+ </ion-item>
35
+
36
+ <!-- Submit Button -->
37
+ <ion-button
38
+ type="submit"
39
+ expand="block"
40
+ class="submit-button"
41
+ [disabled]="companyForm.invalid && isSubmitted || isLoading"
42
+ >
43
+ <ion-spinner *ngIf="isLoading" name="crescent"></ion-spinner>
44
+ <span *ngIf="!isLoading">Register Company</span>
45
+ </ion-button>
46
+
47
+ <!-- Sign Up Link -->
48
+ <div class="signup-link">
49
+ Already have a company code? <a routerLink="/auth/signup">Sign Up</a>
50
+ </div>
51
+ </form>
52
+ </div>
53
+ </ion-content>
@@ -0,0 +1,56 @@
1
+ .company-registration-container {
2
+ max-width: 400px;
3
+ margin: 0 auto;
4
+ padding: 20px 0;
5
+ }
6
+
7
+ .company-form {
8
+ .form-field {
9
+ margin-bottom: 16px;
10
+ --padding-start: 0;
11
+ --padding-end: 0;
12
+ --inner-padding-end: 0;
13
+ }
14
+
15
+ .error-message {
16
+ font-size: 12px;
17
+ padding: 4px 0;
18
+ display: block;
19
+ }
20
+
21
+ .submit-button {
22
+ margin-top: 24px;
23
+ }
24
+ }
25
+
26
+ .signup-link {
27
+ margin-top: 20px;
28
+ text-align: center;
29
+ font-size: 14px;
30
+
31
+ a {
32
+ color: var(--ion-color-primary);
33
+ text-decoration: none;
34
+
35
+ &:hover {
36
+ text-decoration: underline;
37
+ }
38
+ }
39
+ }
40
+
41
+ .status-messages {
42
+ margin: 16px 0;
43
+ --padding-start: 0;
44
+ --padding-end: 0;
45
+ --inner-padding-end: 0;
46
+
47
+ &.error-messages {
48
+ p {
49
+ margin: 4px 0;
50
+ }
51
+ }
52
+ }
53
+
54
+ ion-spinner {
55
+ margin-right: 8px;
56
+ }
@@ -0,0 +1,114 @@
1
+ import { Component, OnInit } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
4
+ import { Router, RouterLink } from '@angular/router';
5
+ import { CreateCompanyMutation } from 'src/app/graphql/mutations/company/createCompany.mutation';
6
+ import { BaseGraphQLPage } from 'src/app/shared/base/base-graphql.page';
7
+ import {
8
+ IonHeader,
9
+ IonToolbar,
10
+ IonTitle,
11
+ IonContent,
12
+ IonButton,
13
+ IonInput,
14
+ IonItem,
15
+ IonLabel,
16
+ IonText,
17
+ IonButtons,
18
+ IonBackButton,
19
+ IonSpinner,
20
+ } from '@ionic/angular/standalone';
21
+
22
+ @Component({
23
+ selector: 'app-company-registration',
24
+ templateUrl: './company-registration.page.html',
25
+ styleUrls: ['./company-registration.page.scss'],
26
+ standalone: true,
27
+ imports: [
28
+ CommonModule,
29
+ ReactiveFormsModule,
30
+ RouterLink,
31
+ IonHeader,
32
+ IonToolbar,
33
+ IonTitle,
34
+ IonContent,
35
+ IonButton,
36
+ IonInput,
37
+ IonItem,
38
+ IonLabel,
39
+ IonText,
40
+ IonButtons,
41
+ IonBackButton,
42
+ IonSpinner,
43
+ ],
44
+ })
45
+ export class CompanyRegistrationPage extends BaseGraphQLPage implements OnInit {
46
+ companyForm: FormGroup;
47
+ isSubmitted = false;
48
+ isLoading = false;
49
+ backendErrors: string[] = [];
50
+
51
+ constructor(
52
+ private formBuilder: FormBuilder,
53
+ private router: Router
54
+ ) {
55
+ super();
56
+ this.companyForm = this.formBuilder.group({
57
+ name: ['', [Validators.required, Validators.minLength(3)]],
58
+ });
59
+ }
60
+
61
+ ngOnInit() {}
62
+
63
+ // Getter for easy access to form fields in the template
64
+ get f() {
65
+ return this.companyForm.controls;
66
+ }
67
+
68
+ async onSubmit() {
69
+ this.isSubmitted = true;
70
+ this.backendErrors = [];
71
+
72
+ if (this.companyForm.valid) {
73
+ this.isLoading = true;
74
+ const companyData = this.companyForm.value;
75
+
76
+ this.executeMutation({
77
+ mutation: CreateCompanyMutation,
78
+ variables: {
79
+ input: {
80
+ name: companyData.name,
81
+ },
82
+ },
83
+ responsePath: 'createCompany',
84
+ successMessage: 'Company registered successfully!',
85
+ errorMessage: 'Company registration failed. Please check the errors and try again.',
86
+ onSuccess: (result: any) => {
87
+ console.log('Company registration result:', result.data.code);
88
+ // After successful company registration, redirect to user registration
89
+ this.router.navigate(['/auth/signup'], { queryParams: { companyCode: result.data.code } });
90
+ },
91
+ onError: (error) => {
92
+ this.backendErrors = this.errorService.errors;
93
+ this.isLoading = false;
94
+ },
95
+ });
96
+ }
97
+ }
98
+
99
+ // Helper method to get error message
100
+ getErrorMessage(control: string): string {
101
+ if (!this.isSubmitted) return '';
102
+
103
+ const formControl = this.f[control];
104
+ if (!formControl || !formControl.errors) return '';
105
+
106
+ if (formControl.errors['required']) return `${control} is required`;
107
+ if (formControl.errors['minlength']) {
108
+ const minLength = formControl.errors['minlength'].requiredLength;
109
+ return `${control} must be at least ${minLength} characters`;
110
+ }
111
+
112
+ return '';
113
+ }
114
+ }
@@ -0,0 +1,37 @@
1
+ const Generator = require('yeoman-generator');
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+
5
+ module.exports = class extends Generator {
6
+ constructor(args, opts) {
7
+ super(args, opts);
8
+ }
9
+
10
+ async prompting() {
11
+ // Set default project name to 'frontend'
12
+ this.answers = {
13
+ projectName: 'frontend'
14
+ };
15
+ }
16
+
17
+ async writing() {
18
+ const { projectName } = this.answers;
19
+ const projectPath = path.join(process.cwd(), projectName);
20
+
21
+ // Copy home page files
22
+ this.fs.copyTpl(
23
+ this.templatePath('src/app/home/home.page.html'),
24
+ path.join(projectPath, 'src/app/home/home.page.html')
25
+ );
26
+
27
+ this.fs.copyTpl(
28
+ this.templatePath('src/app/home/home.page.scss'),
29
+ path.join(projectPath, 'src/app/home/home.page.scss')
30
+ );
31
+
32
+ this.fs.copyTpl(
33
+ this.templatePath('src/app/home/home.page.ts'),
34
+ path.join(projectPath, 'src/app/home/home.page.ts')
35
+ );
36
+ }
37
+ };
@@ -0,0 +1,45 @@
1
+ <ion-header>
2
+ <ion-toolbar>
3
+ <ion-title>Welcome</ion-title>
4
+ </ion-toolbar>
5
+ </ion-header>
6
+
7
+ <ion-content class="ion-padding">
8
+ <div class="welcome-container">
9
+ <h1>Welcome to Rapid Stack</h1>
10
+ <p>Please choose how you'd like to get started:</p>
11
+
12
+ <div class="registration-options">
13
+ <ion-card>
14
+ <ion-card-header>
15
+ <ion-card-title>Register as Company</ion-card-title>
16
+ </ion-card-header>
17
+ <ion-card-content>
18
+ <p>Create a new company account and manage your organization</p>
19
+ <ion-button expand="block" routerLink="/company-registration">
20
+ Register Company
21
+ </ion-button>
22
+ </ion-card-content>
23
+ </ion-card>
24
+
25
+ <ion-card>
26
+ <ion-card-header>
27
+ <ion-card-title>Register as Individual</ion-card-title>
28
+ </ion-card-header>
29
+ <ion-card-content>
30
+ <p>Sign up as an individual user under an existing company</p>
31
+ <ion-button expand="block" routerLink="/auth/signup">
32
+ Register as Individual
33
+ </ion-button>
34
+ </ion-card-content>
35
+ </ion-card>
36
+ </div>
37
+
38
+ <div class="login-section">
39
+ <p>Already have an account?</p>
40
+ <ion-button expand="block" routerLink="/auth/login">
41
+ Login
42
+ </ion-button>
43
+ </div>
44
+ </div>
45
+ </ion-content>
@@ -0,0 +1,94 @@
1
+ #container {
2
+ text-align: center;
3
+
4
+ position: absolute;
5
+ left: 0;
6
+ right: 0;
7
+ top: 50%;
8
+ transform: translateY(-50%);
9
+ }
10
+
11
+ #container strong {
12
+ font-size: 20px;
13
+ line-height: 26px;
14
+ }
15
+
16
+ #container p {
17
+ font-size: 16px;
18
+ line-height: 22px;
19
+
20
+ color: #8c8c8c;
21
+
22
+ margin: 0;
23
+ }
24
+
25
+ #container a {
26
+ text-decoration: none;
27
+ }
28
+
29
+ .welcome-container {
30
+ max-width: 800px;
31
+ margin: 0 auto;
32
+ padding: 2rem 0;
33
+ text-align: center;
34
+
35
+ h1 {
36
+ font-size: 2.5rem;
37
+ margin-bottom: 1rem;
38
+ color: var(--ion-color-primary);
39
+ }
40
+
41
+ p {
42
+ font-size: 1.1rem;
43
+ color: var(--ion-color-medium);
44
+ margin-bottom: 2rem;
45
+ }
46
+ }
47
+
48
+ .registration-options {
49
+ display: grid;
50
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
51
+ gap: 2rem;
52
+ margin-bottom: 3rem;
53
+
54
+ ion-card {
55
+ margin: 0;
56
+ height: 100%;
57
+ display: flex;
58
+ flex-direction: column;
59
+ transition: transform 0.2s ease;
60
+
61
+ &:hover {
62
+ transform: translateY(-5px);
63
+ }
64
+
65
+ ion-card-header {
66
+ flex: 0 0 auto;
67
+ }
68
+
69
+ ion-card-content {
70
+ flex: 1;
71
+ display: flex;
72
+ flex-direction: column;
73
+ justify-content: space-between;
74
+
75
+ p {
76
+ margin-bottom: 1.5rem;
77
+ font-size: 1rem;
78
+ }
79
+
80
+ ion-button {
81
+ margin-top: auto;
82
+ }
83
+ }
84
+ }
85
+ }
86
+
87
+ .login-section {
88
+ text-align: center;
89
+ margin-top: 2rem;
90
+
91
+ p {
92
+ margin-bottom: 1rem;
93
+ }
94
+ }
@@ -0,0 +1,35 @@
1
+ import { Component } from '@angular/core';
2
+ import {
3
+ IonHeader,
4
+ IonToolbar,
5
+ IonTitle,
6
+ IonContent,
7
+ IonCard,
8
+ IonCardHeader,
9
+ IonCardTitle,
10
+ IonCardContent,
11
+ IonButton
12
+ } from '@ionic/angular/standalone';
13
+ import { RouterLink } from '@angular/router';
14
+
15
+ @Component({
16
+ selector: 'app-home',
17
+ templateUrl: 'home.page.html',
18
+ styleUrls: ['home.page.scss'],
19
+ standalone: true,
20
+ imports: [
21
+ IonHeader,
22
+ IonToolbar,
23
+ IonTitle,
24
+ IonContent,
25
+ IonCard,
26
+ IonCardHeader,
27
+ IonCardTitle,
28
+ IonCardContent,
29
+ IonButton,
30
+ RouterLink
31
+ ],
32
+ })
33
+ export class HomePage {
34
+ constructor() {}
35
+ }
@@ -1,7 +1,7 @@
1
1
  import { gql } from 'apollo-angular';
2
2
 
3
3
  export const Create<%= h.toPascalCase(modelName) %>Mutation = gql`
4
- mutation create<%= h.toPascalCase(modelName) %>(
4
+ mutation Create<%= h.toPascalCase(modelName) %>(
5
5
  $input: Create<%= h.toPascalCase(modelName) %>Input!
6
6
  ) {
7
7
  create<%= h.toPascalCase(modelName) %>(input: $input) {
@@ -1,7 +1,7 @@
1
1
  import { gql } from 'apollo-angular';
2
2
 
3
3
  export const Delete<%= h.toPascalCase(modelName) %>Mutation = gql`
4
- mutation delete<%= h.toPascalCase(modelName) %>(
4
+ mutation Delete<%= h.toPascalCase(modelName) %>(
5
5
  $input: Delete<%= h.toPascalCase(modelName) %>Input!
6
6
  ) {
7
7
  delete<%= h.toPascalCase(modelName) %>(input: $input) {
@@ -1,7 +1,7 @@
1
1
  import { gql } from 'apollo-angular';
2
2
 
3
3
  export const List<%= h.toPascalCase(modelName) %>Query = gql`
4
- query list<%= h.toPascalCase(modelName) %>($input: List<%= h.toPascalCase(modelName) %>Input!) {
4
+ query List<%= h.toPascalCase(modelName) %>($input: List<%= h.toPascalCase(modelName) %>Input!) {
5
5
  list<%= h.toPascalCase(modelName) %>(input: $input) {
6
6
  data {
7
7
  id
@@ -1,7 +1,7 @@
1
1
  import { gql } from 'apollo-angular';
2
2
 
3
3
  export const Show<%= h.toPascalCase(modelName) %>Query = gql`
4
- query show<%= h.toPascalCase(modelName) %>($input: Show<%= h.toPascalCase(modelName) %>Input!) {
4
+ query Show<%= h.toPascalCase(modelName) %>($input: Show<%= h.toPascalCase(modelName) %>Input!) {
5
5
  show<%= h.toPascalCase(modelName) %>(input: $input) {
6
6
  data {
7
7
  id
@@ -1,7 +1,7 @@
1
1
  import { gql } from 'apollo-angular';
2
2
 
3
3
  export const Update<%= h.toPascalCase(modelName) %>Mutation = gql`
4
- mutation update<%= h.toPascalCase(modelName) %>(
4
+ mutation Update<%= h.toPascalCase(modelName) %>(
5
5
  $input: Update<%= h.toPascalCase(modelName) %>Input!
6
6
  ) {
7
7
  update<%= h.toPascalCase(modelName) %>(input: $input) {
@@ -2,12 +2,16 @@
2
2
 
3
3
  require "fileutils"
4
4
  require "pathname"
5
+ require_relative "pre_install"
5
6
 
6
7
  module RapidStack
7
8
  module PostInstall
8
9
  def self.install_generators
9
10
  puts "\n=== Starting Rapid Stack Generator Installation ==="
10
11
 
12
+ # Check Node.js requirements first
13
+ RapidStack::PreInstall.check_node_requirements
14
+
11
15
  # Find the generator directory in the installed gem
12
16
  gem_dir = Pathname.new(__dir__).parent.parent
13
17
 
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "open3"
4
+
5
+ module RapidStack
6
+ module PreInstall
7
+ def self.check_node_requirements
8
+ puts "\n=== Checking Node.js Requirements ==="
9
+
10
+ # Check Node.js
11
+ begin
12
+ node_version, _, status = Open3.capture3("node", "--version")
13
+ if status.success?
14
+ puts "✅ Node.js is installed (version: #{node_version.strip})"
15
+ else
16
+ puts "❌ Node.js is not installed"
17
+ puts "Please install Node.js version 18.0.0 or higher"
18
+ puts "Visit: https://nodejs.org/"
19
+ exit 1
20
+ end
21
+ rescue StandardError => e
22
+ puts "❌ Error checking Node.js installation: #{e.message}"
23
+ puts "Please install Node.js version 18.0.0 or higher"
24
+ puts "Visit: https://nodejs.org/"
25
+ exit 1
26
+ end
27
+
28
+ # Check npm
29
+ begin
30
+ npm_version, _, status = Open3.capture3("npm", "--version")
31
+ if status.success?
32
+ puts "✅ npm is installed (version: #{npm_version.strip})"
33
+ else
34
+ puts "❌ npm is not installed"
35
+ puts "Please install npm version 9.0.0 or higher"
36
+ puts "Visit: https://nodejs.org/"
37
+ exit 1
38
+ end
39
+ rescue StandardError => e
40
+ puts "❌ Error checking npm installation: #{e.message}"
41
+ puts "Please install npm version 9.0.0 or higher"
42
+ puts "Visit: https://nodejs.org/"
43
+ exit 1
44
+ end
45
+
46
+ puts "=== Node.js Requirements Check Complete ===\n"
47
+ end
48
+ end
49
+ end
50
+
51
+ # Run the check if this file is being executed directly
52
+ RapidStack::PreInstall.check_node_requirements if __FILE__ == $PROGRAM_NAME
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RapidStack
4
- VERSION = "1.0.3"
4
+ VERSION = "1.0.4"
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rapid_stack
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kingsley Ijomah
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-04-02 00:00:00.000000000 Z
10
+ date: 2025-04-03 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: jwt
@@ -23,6 +23,20 @@ dependencies:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
25
  version: '2.7'
26
+ - !ruby/object:Gem::Dependency
27
+ name: npm
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: 0.1.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 0.1.0
26
40
  - !ruby/object:Gem::Dependency
27
41
  name: rails
28
42
  requirement: !ruby/object:Gem::Requirement
@@ -71,20 +85,6 @@ dependencies:
71
85
  - - "~>"
72
86
  - !ruby/object:Gem::Version
73
87
  version: 0.18.0
74
- - !ruby/object:Gem::Dependency
75
- name: npm
76
- requirement: !ruby/object:Gem::Requirement
77
- requirements:
78
- - - "~>"
79
- - !ruby/object:Gem::Version
80
- version: 0.1.0
81
- type: :development
82
- prerelease: false
83
- version_requirements: !ruby/object:Gem::Requirement
84
- requirements:
85
- - - "~>"
86
- - !ruby/object:Gem::Version
87
- version: 0.1.0
88
88
  - !ruby/object:Gem::Dependency
89
89
  name: rspec
90
90
  requirement: !ruby/object:Gem::Requirement
@@ -314,6 +314,10 @@ files:
314
314
  - lib/rapid_stack/generators/generator-rapid/generators/frontend-auth/templates/signIn.mutation.ts.ejs
315
315
  - lib/rapid_stack/generators/generator-rapid/generators/frontend-auth/templates/updatePassword.mutation.ts.ejs
316
316
  - lib/rapid_stack/generators/generator-rapid/generators/frontend-auth/templates/updateUser.mutation.ts.ejs
317
+ - lib/rapid_stack/generators/generator-rapid/generators/frontend-company/index.js
318
+ - lib/rapid_stack/generators/generator-rapid/generators/frontend-company/templates/src/app/company/company-registration.page.html
319
+ - lib/rapid_stack/generators/generator-rapid/generators/frontend-company/templates/src/app/company/company-registration.page.scss
320
+ - lib/rapid_stack/generators/generator-rapid/generators/frontend-company/templates/src/app/company/company-registration.page.ts
317
321
  - lib/rapid_stack/generators/generator-rapid/generators/frontend-crud/index.js
318
322
  - lib/rapid_stack/generators/generator-rapid/generators/frontend-crud/templates/table-crud/page.html.ejs
319
323
  - lib/rapid_stack/generators/generator-rapid/generators/frontend-crud/templates/table-crud/page.scss.ejs
@@ -323,6 +327,10 @@ files:
323
327
  - lib/rapid_stack/generators/generator-rapid/generators/frontend-event/templates/form.template.ts
324
328
  - lib/rapid_stack/generators/generator-rapid/generators/frontend-event/templates/input.handler.ts
325
329
  - lib/rapid_stack/generators/generator-rapid/generators/frontend-event/templates/input.template.ts
330
+ - lib/rapid_stack/generators/generator-rapid/generators/frontend-home/index.js
331
+ - lib/rapid_stack/generators/generator-rapid/generators/frontend-home/templates/src/app/home/home.page.html
332
+ - lib/rapid_stack/generators/generator-rapid/generators/frontend-home/templates/src/app/home/home.page.scss
333
+ - lib/rapid_stack/generators/generator-rapid/generators/frontend-home/templates/src/app/home/home.page.ts
326
334
  - lib/rapid_stack/generators/generator-rapid/generators/frontend-list-action/index.js
327
335
  - lib/rapid_stack/generators/generator-rapid/generators/frontend-list-action/templates/list-action/list.component.html.ejs
328
336
  - lib/rapid_stack/generators/generator-rapid/generators/frontend-list-action/templates/list-action/list.component.scss.ejs
@@ -15830,6 +15838,7 @@ files:
15830
15838
  - lib/rapid_stack/generators/generator-rapid/package.json
15831
15839
  - lib/rapid_stack/generators/generator-rapid/tsconfig.json
15832
15840
  - lib/rapid_stack/post_install.rb
15841
+ - lib/rapid_stack/pre_install.rb
15833
15842
  - lib/rapid_stack/setup.rb
15834
15843
  - lib/rapid_stack/version.rb
15835
15844
  homepage: https://github.com/kingsley-ijomah/rapid_stack
@@ -15837,14 +15846,18 @@ licenses:
15837
15846
  - MIT
15838
15847
  metadata:
15839
15848
  homepage_uri: https://github.com/kingsley-ijomah/rapid_stack
15840
- source_code_uri: https://github.com/kingsley-ijomah/rapid_stack/tree/v1.0.3
15841
- changelog_uri: https://github.com/kingsley-ijomah/rapid_stack/blob/v1.0.3/CHANGELOG.md
15842
- documentation_uri: https://github.com/kingsley-ijomah/rapid_stack/blob/v1.0.3/README.md
15849
+ source_code_uri: https://github.com/kingsley-ijomah/rapid_stack/tree/v1.0.4
15850
+ changelog_uri: https://github.com/kingsley-ijomah/rapid_stack/blob/v1.0.4/CHANGELOG.md
15851
+ documentation_uri: https://github.com/kingsley-ijomah/rapid_stack/blob/v1.0.4/README.md
15843
15852
  post_install_message: |
15844
15853
  =======================================
15845
15854
  Thank you for installing Rapid Stack!
15846
15855
  =======================================
15847
15856
 
15857
+ Before proceeding, please ensure you have:
15858
+ 1. Node.js version 18.0.0 or higher
15859
+ 2. npm version 9.0.0 or higher
15860
+
15848
15861
  To complete the installation and set up the generators:
15849
15862
 
15850
15863
  1. Run the following command: